diff --git a/tools/server/webui/package-lock.json b/tools/server/webui/package-lock.json index a05cbcfe5c392..236300ecced7b 100644 --- a/tools/server/webui/package-lock.json +++ b/tools/server/webui/package-lock.json @@ -16,6 +16,7 @@ "autoprefixer": "^10.4.20", "daisyui": "^5.0.12", "dexie": "^4.0.11", + "dexie-export-import": "^4.0.11", "highlight.js": "^11.10.0", "katex": "^0.16.15", "pdfjs-dist": "^5.2.133", @@ -2659,6 +2660,15 @@ "integrity": "sha512-SOKO002EqlvBYYKQSew3iymBoN2EQ4BDw/3yprjh7kAfFzjBYkaMNa/pZvcA7HSWlcKSQb9XhPe3wKyQ0x4A8A==", "license": "Apache-2.0" }, + "node_modules/dexie-export-import": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/dexie-export-import/-/dexie-export-import-4.1.4.tgz", + "integrity": "sha512-3bw171qUuOTWSYLXI7C/0M6p1X65Rho3tu1IvD9By8jn0+3t3dLSkDlZ1BC6MbABl3kRlhtGigzC+SF+qcS5Og==", + "license": "Apache-2.0", + "peerDependencies": { + "dexie": "^2.0.4 || ^3.0.0 || ^4.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.91", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.91.tgz", diff --git a/tools/server/webui/package.json b/tools/server/webui/package.json index 8076840324d49..5ccd7b09ca146 100644 --- a/tools/server/webui/package.json +++ b/tools/server/webui/package.json @@ -19,6 +19,7 @@ "autoprefixer": "^10.4.20", "daisyui": "^5.0.12", "dexie": "^4.0.11", + "dexie-export-import": "^4.0.11", "highlight.js": "^11.10.0", "katex": "^0.16.15", "pdfjs-dist": "^5.2.133", diff --git a/tools/server/webui/src/components/SettingDialog.tsx b/tools/server/webui/src/components/SettingDialog.tsx index 45a8d73b00592..af001f095bb21 100644 --- a/tools/server/webui/src/components/SettingDialog.tsx +++ b/tools/server/webui/src/components/SettingDialog.tsx @@ -197,6 +197,76 @@ const SETTING_SECTIONS: SettingSection[] = [ ); }, }, + { + type: SettingInputType.CUSTOM, + key: 'custom', // dummy key, won't be used + component: () => { + const exportDB = async () => { + const blob = await StorageUtils.exportDB(); + const a = document.createElement('a'); + document.body.appendChild(a); + a.href = URL.createObjectURL(blob); + document.body.appendChild(a); + a.download = `aa_dump.json`; + a.click(); + document.body.removeChild(a); + }; + return ( + + ); + }, + }, + { + type: SettingInputType.CUSTOM, + key: 'custom', // dummy key, won't be used + component: () => { + const importDB = async (e: React.ChangeEvent) => { + console.log(e); + if (!e.target.files) { + throw new Error('e.target.files cant be null'); + } + if (e.target.files.length != 1) + throw new Error( + 'Number of selected files for DB import must be 1 but was ' + + e.target.files.length + + '.' + ); + const file = e.target.files[0]; + try { + if (!file) throw new Error('No DB found to import.'); + console.log('Importing DB ' + file.name); + await StorageUtils.importDB(file); + console.log('Import complete'); + window.location.reload(); + } catch (error) { + console.error('' + error); + } + }; + return ( +
+ + +
+ ); + }, + }, { type: SettingInputType.CHECKBOX, label: 'Show tokens per second', diff --git a/tools/server/webui/src/utils/storage.ts b/tools/server/webui/src/utils/storage.ts index 505693e9272ac..680ce73068d81 100644 --- a/tools/server/webui/src/utils/storage.ts +++ b/tools/server/webui/src/utils/storage.ts @@ -4,6 +4,7 @@ import { CONFIG_DEFAULT } from '../Config'; import { Conversation, Message, TimingReport } from './types'; import Dexie, { Table } from 'dexie'; +import { exportDB as exportDexieDB } from 'dexie-export-import'; const event = new EventTarget(); @@ -35,6 +36,16 @@ const StorageUtils = { /** * manage conversations */ + async exportDB() { + return await exportDexieDB(db); + }, + + async importDB(file: File) { + await db.delete(); + await db.open(); + return await db.import(file); + }, + async getAllConversations(): Promise { await migrationLStoIDB().catch(console.error); // noop if already migrated return (await db.conversations.toArray()).sort(