From 677aa6ef512e765f8677d4f97408ea9919841b22 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Wed, 8 May 2024 13:42:59 +0530 Subject: [PATCH] feat: Add export/import functions for chat history, promt and knowledge --- src/assets/locale/en/settings.json | 4 +- src/assets/locale/ja-JP/settings.json | 4 +- src/assets/locale/ml/settings.json | 12 ++-- src/assets/locale/ru/settings.json | 8 +-- src/assets/locale/zh/settings.json | 4 +- src/components/Common/Beta.tsx | 8 +++ .../Layouts/SettingsOptionLayout.tsx | 3 +- src/components/Option/Settings/other.tsx | 40 ++++++++++- src/db/index.ts | 12 ++++ src/db/vector.ts | 20 +++++- src/libs/export-import.ts | 66 +++++++++++++++++++ 11 files changed, 159 insertions(+), 22 deletions(-) create mode 100644 src/components/Common/Beta.tsx create mode 100644 src/libs/export-import.ts diff --git a/src/assets/locale/en/settings.json b/src/assets/locale/en/settings.json index a2b35a0..589f557 100644 --- a/src/assets/locale/en/settings.json +++ b/src/assets/locale/en/settings.json @@ -41,12 +41,12 @@ "confirm": "Are you sure you want to delete your chat history? This action cannot be undone." }, "export": { - "label": "Export Chat History, Settings, and Prompts", + "label": "Export Chat History, Knowledge Base, and Prompts", "button": "Export Data", "success": "Export Success" }, "import": { - "label": "Import Chat History, Settings, and Prompts", + "label": "Import Chat History, Knowledge Base, and Prompts", "button": "Import Data", "success": "Import Success", "error": "Import Error" diff --git a/src/assets/locale/ja-JP/settings.json b/src/assets/locale/ja-JP/settings.json index 34c8a99..1fae4f5 100644 --- a/src/assets/locale/ja-JP/settings.json +++ b/src/assets/locale/ja-JP/settings.json @@ -44,12 +44,12 @@ "confirm": "チャット履歴を削除してもよろしいですか?この操作は元に戻せません。" }, "export": { - "label": "チャット履歴、設定、プロンプトをエクスポートする", + "label": "チャット履歴、知識ベース、プロンプトをエクスポート", "button": "データをエクスポート", "success": "エクスポート成功" }, "import": { - "label": "チャット履歴、設定、プロンプトをインポートする", + "label": "チャット履歴、知識ベース、プロンプトをインポート", "button": "データをインポート", "success": "インポート成功", "error": "インポートエラー" diff --git a/src/assets/locale/ml/settings.json b/src/assets/locale/ml/settings.json index 5994d0c..97152cd 100644 --- a/src/assets/locale/ml/settings.json +++ b/src/assets/locale/ml/settings.json @@ -44,16 +44,16 @@ "confirm": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് ഉറപ്പാണോ? ഈ പ്രവർത്തനം പിന്നീട് പിന്വലിക്കാനാവില്ല." }, "export": { - "label": "ചാറ്റ് ചരിത്രം, ക്രമീകരണങ്ങൾ, പ്രോംപ്റ്റുകൾ എക്സ്പോർട്ട് ചെയ്യുക", + "label": "ചാറ്റ് ചരിത്രം, അറിവ് അടിസ്ഥാനം, പ്രോംപ്റ്റുകൾ എക്സ്പോർട്ട് ചെയ്യുക", "button": "ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക", "success": "എക്സ്പോർട്ട് വിജയകരമായി" - }, - "import": { - "label": "ചാറ്റ് ചരിത്രം, ക്രമീകരണങ്ങൾ, പ്രോംപ്റ്റുകൾ ഇമ്പോർട്ട് ചെയ്യുക", + }, + "import": { + "label": "ചാറ്റ് ചരിത്രം, അറിവ് അടിസ്ഥാനം, പ്രോംപ്റ്റുകൾ ഇമ്പോർട്ട് ചെയ്യുക", "button": "ഡാറ്റ ഇമ്പോർട്ട് ചെയ്യുക", "success": "ഇമ്പോർട്ട് വിജയകരമായി", - "error": "ഇമ്പോർട്ട് പരാജയപ്പെട്ടു" - } + "error": "ഇമ്പോർട്ട് പിശക്" + } }, "tts": { "heading": "ടെക്സ്റ്റ്-ടു-സ്പീച്ച് ക്രമീകരണങ്ങൾ", diff --git a/src/assets/locale/ru/settings.json b/src/assets/locale/ru/settings.json index dee3775..c48c357 100644 --- a/src/assets/locale/ru/settings.json +++ b/src/assets/locale/ru/settings.json @@ -41,13 +41,13 @@ "confirm": "Вы уверены, что хотите удалить историю чата? Это действие нельзя отменить." }, "export": { - "label": "Экспорт истории чата, настроек и подсказок", - "button": "Экспорт данных", + "label": "Экспорт истории чата, базы знаний и подсказок", + "button": "Экспортировать данные", "success": "Экспорт успешен" }, "import": { - "label": "Импорт истории чата, настроек и подсказок", - "button": "Импорт данных", + "label": "Импорт истории чата, базы знаний и подсказок", + "button": "Импортировать данные", "success": "Импорт успешен", "error": "Ошибка импорта" } diff --git a/src/assets/locale/zh/settings.json b/src/assets/locale/zh/settings.json index 444814f..70b8d3c 100644 --- a/src/assets/locale/zh/settings.json +++ b/src/assets/locale/zh/settings.json @@ -44,12 +44,12 @@ "confirm": "您确定要删除聊天记录吗?此操作无法撤销。" }, "export": { - "label": "导出聊天记录、设置和提示", + "label": "导出聊天记录、知识库和提示", "button": "导出数据", "success": "导出成功" }, "import": { - "label": "导入聊天记录、设置和提示", + "label": "导入聊天记录、知识库和提示", "button": "导入数据", "success": "导入成功", "error": "导入错误" diff --git a/src/components/Common/Beta.tsx b/src/components/Common/Beta.tsx new file mode 100644 index 0000000..c381ae3 --- /dev/null +++ b/src/components/Common/Beta.tsx @@ -0,0 +1,8 @@ +import { Tag } from "antd" +import { useTranslation } from "react-i18next" + +export const BetaTag = () => { + const { t } = useTranslation("common") + + return {t("beta")} +} diff --git a/src/components/Layouts/SettingsOptionLayout.tsx b/src/components/Layouts/SettingsOptionLayout.tsx index 051fdbb..fa074cf 100644 --- a/src/components/Layouts/SettingsOptionLayout.tsx +++ b/src/components/Layouts/SettingsOptionLayout.tsx @@ -10,6 +10,7 @@ import { useTranslation } from "react-i18next" import { Link, useLocation } from "react-router-dom" import { OllamaIcon } from "../Icons/Ollama" import { Tag } from "antd" +import { BetaTag } from "../Common/Beta" function classNames(...classes: string[]) { return classes.filter(Boolean).join(" ") @@ -81,7 +82,7 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => { name={
{t("manageKnowledge.title")} - {t("common:beta")} +
} icon={BlocksIcon} diff --git a/src/components/Option/Settings/other.tsx b/src/components/Option/Settings/other.tsx index 65383f0..e33b389 100644 --- a/src/components/Option/Settings/other.tsx +++ b/src/components/Option/Settings/other.tsx @@ -9,6 +9,11 @@ import { SearchModeSettings } from "./search-mode" import { useTranslation } from "react-i18next" import { useI18n } from "@/hooks/useI18n" import { TTSModeSettings } from "./tts-mode" +import { + exportPageAssistData, + importPageAssistData +} from "@/libs/export-import" +import { BetaTag } from "@/components/Common/Beta" export const SettingOther = () => { const { clearChat, speechToTextLanguage, setSpeechToTextLanguage } = @@ -90,7 +95,7 @@ export const SettingOther = () => { - +

@@ -98,7 +103,7 @@ export const SettingOther = () => {

-
+
{t("generalSettings.system.deleteChatHistory.label")} @@ -122,6 +127,37 @@ export const SettingOther = () => { {t("generalSettings.system.deleteChatHistory.button")}
+
+ + {t("generalSettings.system.export.label")} + + +
+
+ + {t("generalSettings.system.import.label")} + + + { + if (e.target.files) { + importPageAssistData(e.target.files[0]) + } + }} + /> +
) diff --git a/src/db/index.ts b/src/db/index.ts index bc8b2f8..6ca341f 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -444,3 +444,15 @@ export const importChatHistory = async ( } } } + +export const exportPrompts = async () => { + const db = new PageAssitDatabase() + return await db.getAllPrompts() +} + +export const importPrompts = async (prompts: Prompts) => { + const db = new PageAssitDatabase() + for (const prompt of prompts) { + await db.addPrompt(prompt) + } +} diff --git a/src/db/vector.ts b/src/db/vector.ts index 2c2e281..09624fc 100644 --- a/src/db/vector.ts +++ b/src/db/vector.ts @@ -112,6 +112,22 @@ export class PageAssistVectorDb { }) }) } + + saveImportedData = async (data: VectorData[]): Promise => { + return new Promise((resolve, reject) => { + const obj: Record = {} + data.forEach((d) => { + obj[d.id] = d + }) + this.db.set(obj, () => { + if (chrome.runtime.lastError) { + reject(chrome.runtime.lastError) + } else { + resolve() + } + }) + }) + } } export const insertVector = async ( @@ -148,7 +164,5 @@ export const exportVectors = async () => { export const importVectors = async (data: VectorData[]) => { const db = new PageAssistVectorDb() - for (const d of data) { - await db.insertVector(d.id, d.vectors) - } + return db.saveImportedData(data) } diff --git a/src/libs/export-import.ts b/src/libs/export-import.ts new file mode 100644 index 0000000..50bda8b --- /dev/null +++ b/src/libs/export-import.ts @@ -0,0 +1,66 @@ +import { + exportChatHistory, + exportPrompts, + importChatHistory, + importPrompts +} from "@/db" +import { exportKnowledge, importKnowledge } from "@/db/knowledge" +import { exportVectors, importVectors } from "@/db/vector" +import { message } from "antd" + +export const exportPageAssistData = async () => { + const knowledge = await exportKnowledge() + const chat = await exportChatHistory() + const vector = await exportVectors() + const prompts = await exportPrompts() + + const data = { + knowledge, + chat, + vector, + prompts + } + + const dataStr = JSON.stringify(data) + + const blob = new Blob([dataStr], { type: "application/json" }) + const url = URL.createObjectURL(blob) + + const a = document.createElement("a") + a.href = url + a.download = `page-assist-${new Date().toISOString()}.json` + a.click() + URL.revokeObjectURL(url) +} + +export const importPageAssistData = async (file: File) => { + const reader = new FileReader() + reader.onload = async () => { + try { + const data = JSON.parse(reader.result as string) + + if (data?.knowledge) { + await importKnowledge(data.knowledge) + } + + if (data?.chat) { + await importChatHistory(data.chat) + } + + if (data?.vector) { + await importVectors(data.vector) + } + + if (data?.prompts) { + await importPrompts(data.prompts) + } + + message.success("Data imported successfully") + } catch (e) { + console.error(e) + message.error("Failed to import data") + } + } + + reader.readAsText(file) +}