From a1bd1b90880fcdd71b825430d96b1484000e0584 Mon Sep 17 00:00:00 2001 From: Chek Wei Tan Date: Thu, 19 Oct 2023 07:55:34 +0800 Subject: [PATCH] refactor: Use IndexedDB as storage (#576) --- package-lock.json | 110 ++++- package.json | 4 + src/App.vue | 18 +- src/bots/Bot.js | 5 +- src/components/ChatAction.vue | 10 +- src/components/ChatDrawer/ChatDrawer.vue | 80 ++-- src/components/ChatDrawer/ChatDrawerItem.vue | 48 +- src/components/ChatSetting.vue | 1 + src/components/Footer/FooterBar.vue | 46 +- src/components/Messages/ChatMessages.vue | 140 +++--- src/components/Messages/ChatPrompt.vue | 4 +- src/components/Messages/ChatResponse.vue | 191 ++++---- src/components/Messages/ChatResponses.vue | 52 --- src/components/Messages/ChatThread.vue | 103 +++-- src/components/PromptModal.vue | 20 +- src/i18n/locales/en.json | 6 +- src/i18n/locales/zh.json | 3 +- src/main.js | 10 +- src/store/chats.js | 62 +++ src/store/db.js | 10 + src/store/index.js | 437 ++++++++----------- src/store/messages.js | 37 ++ src/store/messagesPersist.js | 10 - src/store/migration.js | 100 +++++ src/store/promptsPersist.js | 10 - src/store/threads.js | 28 ++ 26 files changed, 922 insertions(+), 623 deletions(-) delete mode 100644 src/components/Messages/ChatResponses.vue create mode 100644 src/store/chats.js create mode 100644 src/store/db.js create mode 100644 src/store/messages.js delete mode 100644 src/store/messagesPersist.js create mode 100644 src/store/migration.js delete mode 100644 src/store/promptsPersist.js create mode 100644 src/store/threads.js diff --git a/package-lock.json b/package-lock.json index c645ff1dbf..6850674bad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,15 +12,19 @@ "dependencies": { "@kangc/v-md-editor": "^2.3.16", "@mdi/font": "^7.2.96", + "@vueuse/rxjs": "^10.4.1", "async-lock": "^1.4.0", "axios": "^1.5.1", "babel-plugin-prismjs": "^2.1.0", "compare-versions": "^6.1.0", "core-js": "^3.32.2", + "dexie": "^4.0.1-alpha.25", "electron-builder": "^24.6.4", "katex": "^0.16.8", "langchain": "~0.0.156", + "localforage": "^1.10.0", "material-design-icons": "^3.0.1", + "rxjs": "^7.8.1", "sortablejs": "^1.15.0", "update-electron-app": "^2.0.1", "uuid": "^9.0.1", @@ -5104,6 +5108,82 @@ "node": ">= 4.0.0" } }, + "node_modules/@vueuse/rxjs": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@vueuse/rxjs/-/rxjs-10.4.1.tgz", + "integrity": "sha512-UU2v4qNKlVjpI9MUYVJ2lAd59IZ29ALwumh5POjaUaqZ+Sapg1+2pscxU7gVDX5pTcTvQ7LPpxDujfS8BSJ/rw==", + "dependencies": { + "@vueuse/shared": "10.4.1", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "rxjs": ">=6.0.0" + } + }, + "node_modules/@vueuse/rxjs/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/shared": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.4.1.tgz", + "integrity": "sha512-vz5hbAM4qA0lDKmcr2y3pPdU+2EVw/yzfRsBdu+6+USGa4PxqSQRYIUC9/NcT06y+ZgaTsyURw2I9qOFaaXHAg==", + "dependencies": { + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -9073,6 +9153,11 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "devOptional": true }, + "node_modules/dexie": { + "version": "4.0.1-alpha.25", + "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.1-alpha.25.tgz", + "integrity": "sha512-udAExYYfJaC6IzVC+ygHdlWYoYxhwYHtiITkthGgSH7dh2FBk3qqDGkJ/Mn2lfxsmATcq9qJDUjyO7yWOo/ZPA==" + }, "node_modules/digest-fetch": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/digest-fetch/-/digest-fetch-1.3.0.tgz", @@ -12293,8 +12378,7 @@ "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -14202,6 +14286,22 @@ "json5": "lib/cli.js" } }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "dependencies": { + "lie": "3.1.1" + } + }, + "node_modules/localforage/node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", @@ -17917,9 +18017,8 @@ }, "node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.1.tgz", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, "dependencies": { "tslib": "^2.1.0" } @@ -19827,8 +19926,7 @@ "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tunnel-agent": { "version": "0.6.0", diff --git a/package.json b/package.json index 240a206b51..fe064e5f41 100644 --- a/package.json +++ b/package.json @@ -27,15 +27,19 @@ "dependencies": { "@kangc/v-md-editor": "^2.3.16", "@mdi/font": "^7.2.96", + "@vueuse/rxjs": "^10.4.1", "async-lock": "^1.4.0", "axios": "^1.5.1", "babel-plugin-prismjs": "^2.1.0", "compare-versions": "^6.1.0", "core-js": "^3.32.2", + "dexie": "^4.0.1-alpha.25", "electron-builder": "^24.6.4", "katex": "^0.16.8", "langchain": "~0.0.156", + "localforage": "^1.10.0", "material-design-icons": "^3.0.1", + "rxjs": "^7.8.1", "sortablejs": "^1.15.0", "update-electron-app": "^2.0.1", "uuid": "^9.0.1", diff --git a/src/App.vue b/src/App.vue index 6f94eb78ea..4a5a29d7a9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -120,12 +120,10 @@ - + @@ -162,6 +160,9 @@ import { } from "./components/ShortcutGuide/shortcut.const"; import i18n from "./i18n"; +import Chats from "@/store/chats"; +import { useObservable } from "@vueuse/rxjs"; +import { liveQuery } from "dexie"; // Components import ChatDrawer from "@/components/ChatDrawer/ChatDrawer.vue"; @@ -187,6 +188,15 @@ const onUpdatedSystemTheme = async () => { applyTheme(resolvedTheme, vuetifyTheme); }; +const currentChat = useObservable( + liveQuery(() => { + const chat = Chats.table.orderBy("selectedTime").last(); + console.log("chat changed"); + return chat; + }), + { initialValue: {} }, +); + ipcRenderer.on("on-updated-system-theme", onUpdatedSystemTheme); const confirmModal = ref(null); diff --git a/src/bots/Bot.js b/src/bots/Bot.js index f1aa60211b..0734ed7608 100644 --- a/src/bots/Bot.js +++ b/src/bots/Bot.js @@ -1,5 +1,6 @@ import i18n from "@/i18n"; import store from "@/store"; +import Chats from "@/store/chats"; export default class Bot { static _logoPackedPaths = null; @@ -247,7 +248,9 @@ export default class Bot { * @returns {object} - Chat context defined by the bot */ async getChatContext(createIfNotExists = true) { - let context = store.getters.currentChat?.contexts?.[this.getClassname()]; + let context = (await Chats.getCurrentChat())?.contexts?.[ + this.getClassname() + ]; if (!context && createIfNotExists) { context = await this.createChatContext(); this.setChatContext(context); diff --git a/src/components/ChatAction.vue b/src/components/ChatAction.vue index 9e62cb5070..cf0aadb4a1 100644 --- a/src/components/ChatAction.vue +++ b/src/components/ChatAction.vue @@ -83,6 +83,7 @@ import { preview } from "../helpers/template-helper"; import ChatPrompt from "@/components/Messages/ChatPrompt.vue"; import BotLogo from "@/components/Footer/BotLogo.vue"; import _bots from "@/bots"; +import Chats from "@/store/chats"; const store = useStore(); const isEdit = ref(false); @@ -140,8 +141,10 @@ function closeDialog(value) { } async function send() { + let newChatIndex; if (chatRef.value === "new") { - await store.dispatch("createChatAndSelect"); + newChatIndex = await Chats.add(); + store.commit("selectChat", newChatIndex); } await store .dispatch("sendPrompt", { @@ -151,7 +154,10 @@ async function send() { .then(() => { if (chatRef.value === "new") { store.commit("editChatTitle", { - title: previewTextarea.value.substring(0, 30), + index: newChatIndex, + payload: { + title: previewTextarea.value.substring(0, 30), + }, }); } }); diff --git a/src/components/ChatDrawer/ChatDrawer.vue b/src/components/ChatDrawer/ChatDrawer.vue index 77aabe26f5..90d34b0681 100644 --- a/src/components/ChatDrawer/ChatDrawer.vue +++ b/src/components/ChatDrawer/ChatDrawer.vue @@ -6,8 +6,8 @@ density="comfortable" class="mb-1 border" :title="$t('chat.newChat')" - @click="onAddNewChat" - @shortkey="onAddNewChat" + @click="onAddChat" + @shortkey="onAddChat" v-shortkey="SHORTCUT_NEW_CHAT.key" >