feat: Add export/import functions for chat history, promt and knowledge
This commit is contained in:
		
							parent
							
								
									11147fd951
								
							
						
					
					
						commit
						677aa6ef51
					
				| @ -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" | ||||
|  | ||||
| @ -44,12 +44,12 @@ | ||||
|                 "confirm": "チャット履歴を削除してもよろしいですか?この操作は元に戻せません。" | ||||
|             }, | ||||
|             "export": { | ||||
|                 "label": "チャット履歴、設定、プロンプトをエクスポートする", | ||||
|                 "label": "チャット履歴、知識ベース、プロンプトをエクスポート", | ||||
|                 "button": "データをエクスポート", | ||||
|                 "success": "エクスポート成功" | ||||
|             }, | ||||
|             "import": { | ||||
|                 "label": "チャット履歴、設定、プロンプトをインポートする", | ||||
|                 "label": "チャット履歴、知識ベース、プロンプトをインポート", | ||||
|                 "button": "データをインポート", | ||||
|                 "success": "インポート成功", | ||||
|                 "error": "インポートエラー" | ||||
|  | ||||
| @ -44,16 +44,16 @@ | ||||
|                 "confirm": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് ഉറപ്പാണോ? ഈ പ്രവർത്തനം പിന്നീട് പിന്വലിക്കാനാവില്ല." | ||||
|             }, | ||||
|             "export": { | ||||
|                 "label": "ചാറ്റ് ചരിത്രം, ക്രമീകരണങ്ങൾ, പ്രോംപ്റ്റുകൾ എക്സ്പോർട്ട് ചെയ്യുക", | ||||
|                 "label": "ചാറ്റ് ചരിത്രം, അറിവ് അടിസ്ഥാനം, പ്രോംപ്റ്റുകൾ എക്സ്പോർട്ട് ചെയ്യുക", | ||||
|                 "button": "ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക", | ||||
|                 "success": "എക്സ്പോർട്ട് വിജയകരമായി" | ||||
|             }, | ||||
|             "import": { | ||||
|                 "label": "ചാറ്റ് ചരിത്രം, ക്രമീകരണങ്ങൾ, പ്രോംപ്റ്റുകൾ ഇമ്പോർട്ട് ചെയ്യുക", | ||||
|               }, | ||||
|               "import": { | ||||
|                 "label": "ചാറ്റ് ചരിത്രം, അറിവ് അടിസ്ഥാനം, പ്രോംപ്റ്റുകൾ ഇമ്പോർട്ട് ചെയ്യുക", | ||||
|                 "button": "ഡാറ്റ ഇമ്പോർട്ട് ചെയ്യുക", | ||||
|                 "success": "ഇമ്പോർട്ട് വിജയകരമായി", | ||||
|                 "error": "ഇമ്പോർട്ട് പരാജയപ്പെട്ടു" | ||||
|             } | ||||
|                 "error": "ഇമ്പോർട്ട് പിശക്" | ||||
|               } | ||||
|         }, | ||||
|         "tts": { | ||||
|             "heading": "ടെക്സ്റ്റ്-ടു-സ്പീച്ച് ക്രമീകരണങ്ങൾ", | ||||
|  | ||||
| @ -41,13 +41,13 @@ | ||||
|                 "confirm": "Вы уверены, что хотите удалить историю чата? Это действие нельзя отменить." | ||||
|             }, | ||||
|             "export": { | ||||
|                 "label": "Экспорт истории чата, настроек и подсказок", | ||||
|                 "button": "Экспорт данных", | ||||
|                 "label": "Экспорт истории чата, базы знаний и подсказок", | ||||
|                 "button": "Экспортировать данные", | ||||
|                 "success": "Экспорт успешен" | ||||
|             }, | ||||
|             "import": { | ||||
|                 "label": "Импорт истории чата, настроек и подсказок", | ||||
|                 "button": "Импорт данных", | ||||
|                 "label": "Импорт истории чата, базы знаний и подсказок", | ||||
|                 "button": "Импортировать данные", | ||||
|                 "success": "Импорт успешен", | ||||
|                 "error": "Ошибка импорта" | ||||
|             } | ||||
|  | ||||
| @ -44,12 +44,12 @@ | ||||
|                 "confirm": "您确定要删除聊天记录吗?此操作无法撤销。" | ||||
|             }, | ||||
|             "export": { | ||||
|                 "label": "导出聊天记录、设置和提示", | ||||
|                 "label": "导出聊天记录、知识库和提示", | ||||
|                 "button": "导出数据", | ||||
|                 "success": "导出成功" | ||||
|             }, | ||||
|             "import": { | ||||
|                 "label": "导入聊天记录、设置和提示", | ||||
|                 "label": "导入聊天记录、知识库和提示", | ||||
|                 "button": "导入数据", | ||||
|                 "success": "导入成功", | ||||
|                 "error": "导入错误" | ||||
|  | ||||
							
								
								
									
										8
									
								
								src/components/Common/Beta.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/components/Common/Beta.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| import { Tag } from "antd" | ||||
| import { useTranslation } from "react-i18next" | ||||
| 
 | ||||
| export const BetaTag = () => { | ||||
|   const { t } = useTranslation("common") | ||||
| 
 | ||||
|   return <Tag color="yellow">{t("beta")}</Tag> | ||||
| } | ||||
| @ -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={ | ||||
|                   <div className="inline-flex items-center gap-2"> | ||||
|                     {t("manageKnowledge.title")} | ||||
|                     <Tag color="yellow">{t("common:beta")}</Tag> | ||||
|                     <BetaTag /> | ||||
|                   </div> | ||||
|                 } | ||||
|                 icon={BlocksIcon} | ||||
|  | ||||
| @ -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 = () => { | ||||
|         </button> | ||||
|       </div> | ||||
|       <SearchModeSettings /> | ||||
|       <TTSModeSettings  /> | ||||
|       <TTSModeSettings /> | ||||
|       <div> | ||||
|         <div className="mb-5"> | ||||
|           <h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white"> | ||||
| @ -98,7 +103,7 @@ export const SettingOther = () => { | ||||
|           </h2> | ||||
|           <div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div> | ||||
|         </div> | ||||
|         <div className="flex flex-row justify-between"> | ||||
|         <div className="flex flex-row mb-3 justify-between"> | ||||
|           <span className="text-gray-500 dark:text-neutral-50 "> | ||||
|             {t("generalSettings.system.deleteChatHistory.label")} | ||||
|           </span> | ||||
| @ -122,6 +127,37 @@ export const SettingOther = () => { | ||||
|             {t("generalSettings.system.deleteChatHistory.button")} | ||||
|           </button> | ||||
|         </div> | ||||
|         <div className="flex flex-row mb-3 justify-between"> | ||||
|           <span className="text-gray-500 dark:text-neutral-50 "> | ||||
|           <BetaTag />    {t("generalSettings.system.export.label")} | ||||
|           </span> | ||||
|           <button | ||||
|             onClick={exportPageAssistData} | ||||
|             className="bg-gray-800 dark:bg-white text-white dark:text-gray-900 px-4 py-2 rounded-md cursor-pointer"> | ||||
|             {t("generalSettings.system.export.button")} | ||||
|           </button> | ||||
|         </div> | ||||
|         <div className="flex flex-row mb-3 justify-between"> | ||||
|           <span className="text-gray-500 dark:text-neutral-50 "> | ||||
|           <BetaTag /> {t("generalSettings.system.import.label")} | ||||
|           </span> | ||||
|           <label | ||||
|             htmlFor="import" | ||||
|             className="bg-gray-800 dark:bg-white text-white dark:text-gray-900 px-4 py-2 rounded-md cursor-pointer"> | ||||
|             {t("generalSettings.system.import.button")} | ||||
|           </label> | ||||
|           <input | ||||
|             type="file" | ||||
|             accept=".json" | ||||
|             id="import" | ||||
|             className="hidden" | ||||
|             onChange={(e) => { | ||||
|               if (e.target.files) { | ||||
|                 importPageAssistData(e.target.files[0]) | ||||
|               } | ||||
|             }} | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|     </dl> | ||||
|   ) | ||||
|  | ||||
| @ -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) | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -112,6 +112,22 @@ export class PageAssistVectorDb { | ||||
|       }) | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   saveImportedData = async (data: VectorData[]): Promise<void> => { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       const obj: Record<string, VectorData> = {} | ||||
|       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)  | ||||
| } | ||||
|  | ||||
							
								
								
									
										66
									
								
								src/libs/export-import.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/libs/export-import.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user