commit
b982ce158b
@ -37,7 +37,7 @@
|
|||||||
"langchain": "^0.1.28",
|
"langchain": "^0.1.28",
|
||||||
"lucide-react": "^0.350.0",
|
"lucide-react": "^0.350.0",
|
||||||
"ml-distance": "^4.0.1",
|
"ml-distance": "^4.0.1",
|
||||||
"pdfjs-dist": "^4.0.379",
|
"pdfjs-dist": "4.0.379",
|
||||||
"property-information": "^6.4.1",
|
"property-information": "^6.4.1",
|
||||||
"pubsub-js": "^1.9.4",
|
"pubsub-js": "^1.9.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
@ -41,12 +41,12 @@
|
|||||||
"confirm": "Are you sure you want to delete your chat history? This action cannot be undone."
|
"confirm": "Are you sure you want to delete your chat history? This action cannot be undone."
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"label": "Export Chat History, Settings, and Prompts",
|
"label": "Export Chat History, Knowledge Base, and Prompts",
|
||||||
"button": "Export Data",
|
"button": "Export Data",
|
||||||
"success": "Export Success"
|
"success": "Export Success"
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"label": "Import Chat History, Settings, and Prompts",
|
"label": "Import Chat History, Knowledge Base, and Prompts",
|
||||||
"button": "Import Data",
|
"button": "Import Data",
|
||||||
"success": "Import Success",
|
"success": "Import Success",
|
||||||
"error": "Import Error"
|
"error": "Import Error"
|
||||||
|
@ -44,12 +44,12 @@
|
|||||||
"confirm": "チャット履歴を削除してもよろしいですか?この操作は元に戻せません。"
|
"confirm": "チャット履歴を削除してもよろしいですか?この操作は元に戻せません。"
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"label": "チャット履歴、設定、プロンプトをエクスポートする",
|
"label": "チャット履歴、知識ベース、プロンプトをエクスポート",
|
||||||
"button": "データをエクスポート",
|
"button": "データをエクスポート",
|
||||||
"success": "エクスポート成功"
|
"success": "エクスポート成功"
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"label": "チャット履歴、設定、プロンプトをインポートする",
|
"label": "チャット履歴、知識ベース、プロンプトをインポート",
|
||||||
"button": "データをインポート",
|
"button": "データをインポート",
|
||||||
"success": "インポート成功",
|
"success": "インポート成功",
|
||||||
"error": "インポートエラー"
|
"error": "インポートエラー"
|
||||||
|
@ -44,15 +44,15 @@
|
|||||||
"confirm": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് ഉറപ്പാണോ? ഈ പ്രവർത്തനം പിന്നീട് പിന്വലിക്കാനാവില്ല."
|
"confirm": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് ഉറപ്പാണോ? ഈ പ്രവർത്തനം പിന്നീട് പിന്വലിക്കാനാവില്ല."
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"label": "ചാറ്റ് ചരിത്രം, ക്രമീകരണങ്ങൾ, പ്രോംപ്റ്റുകൾ എക്സ്പോർട്ട് ചെയ്യുക",
|
"label": "ചാറ്റ് ചരിത്രം, അറിവ് അടിസ്ഥാനം, പ്രോംപ്റ്റുകൾ എക്സ്പോർട്ട് ചെയ്യുക",
|
||||||
"button": "ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക",
|
"button": "ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക",
|
||||||
"success": "എക്സ്പോർട്ട് വിജയകരമായി"
|
"success": "എക്സ്പോർട്ട് വിജയകരമായി"
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"label": "ചാറ്റ് ചരിത്രം, ക്രമീകരണങ്ങൾ, പ്രോംപ്റ്റുകൾ ഇമ്പോർട്ട് ചെയ്യുക",
|
"label": "ചാറ്റ് ചരിത്രം, അറിവ് അടിസ്ഥാനം, പ്രോംപ്റ്റുകൾ ഇമ്പോർട്ട് ചെയ്യുക",
|
||||||
"button": "ഡാറ്റ ഇമ്പോർട്ട് ചെയ്യുക",
|
"button": "ഡാറ്റ ഇമ്പോർട്ട് ചെയ്യുക",
|
||||||
"success": "ഇമ്പോർട്ട് വിജയകരമായി",
|
"success": "ഇമ്പോർട്ട് വിജയകരമായി",
|
||||||
"error": "ഇമ്പോർട്ട് പരാജയപ്പെട്ടു"
|
"error": "ഇമ്പോർട്ട് പിശക്"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tts": {
|
"tts": {
|
||||||
|
@ -41,13 +41,13 @@
|
|||||||
"confirm": "Вы уверены, что хотите удалить историю чата? Это действие нельзя отменить."
|
"confirm": "Вы уверены, что хотите удалить историю чата? Это действие нельзя отменить."
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"label": "Экспорт истории чата, настроек и подсказок",
|
"label": "Экспорт истории чата, базы знаний и подсказок",
|
||||||
"button": "Экспорт данных",
|
"button": "Экспортировать данные",
|
||||||
"success": "Экспорт успешен"
|
"success": "Экспорт успешен"
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"label": "Импорт истории чата, настроек и подсказок",
|
"label": "Импорт истории чата, базы знаний и подсказок",
|
||||||
"button": "Импорт данных",
|
"button": "Импортировать данные",
|
||||||
"success": "Импорт успешен",
|
"success": "Импорт успешен",
|
||||||
"error": "Ошибка импорта"
|
"error": "Ошибка импорта"
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@
|
|||||||
"confirm": "您确定要删除聊天记录吗?此操作无法撤销。"
|
"confirm": "您确定要删除聊天记录吗?此操作无法撤销。"
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"label": "导出聊天记录、设置和提示",
|
"label": "导出聊天记录、知识库和提示",
|
||||||
"button": "导出数据",
|
"button": "导出数据",
|
||||||
"success": "导出成功"
|
"success": "导出成功"
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"label": "导入聊天记录、设置和提示",
|
"label": "导入聊天记录、知识库和提示",
|
||||||
"button": "导入数据",
|
"button": "导入数据",
|
||||||
"success": "导入成功",
|
"success": "导入成功",
|
||||||
"error": "导入错误"
|
"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>
|
||||||
|
}
|
63
src/components/Common/ModelSelect.tsx
Normal file
63
src/components/Common/ModelSelect.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query"
|
||||||
|
import { Dropdown, Tooltip } from "antd"
|
||||||
|
import { LucideBrain } from "lucide-react"
|
||||||
|
import React from "react"
|
||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { OllamaIcon } from "../Icons/Ollama"
|
||||||
|
import { fetchChatModels } from "@/services/ollama"
|
||||||
|
import { useMessage } from "@/hooks/useMessage"
|
||||||
|
|
||||||
|
export const ModelSelect: React.FC = () => {
|
||||||
|
const { t } = useTranslation("common")
|
||||||
|
const { setSelectedModel, selectedModel } = useMessage()
|
||||||
|
const { data } = useQuery({
|
||||||
|
queryKey: ["getAllModelsForSelect"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const models = await fetchChatModels({ returnEmpty: false })
|
||||||
|
return models
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{data && data.length > 0 && (
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items:
|
||||||
|
data?.map((d) => ({
|
||||||
|
key: d.name,
|
||||||
|
label: (
|
||||||
|
<div className="w-52 gap-2 text-lg truncate inline-flex line-clamp-3 items-center dark:border-gray-700">
|
||||||
|
<div>
|
||||||
|
<OllamaIcon className="h-6 w-6 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
{d.name}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
if (selectedModel === d.name) {
|
||||||
|
setSelectedModel(null)
|
||||||
|
} else {
|
||||||
|
setSelectedModel(d.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})) || [],
|
||||||
|
style: {
|
||||||
|
maxHeight: 500,
|
||||||
|
overflowY: "scroll"
|
||||||
|
},
|
||||||
|
className: "no-scrollbar",
|
||||||
|
activeKey: selectedModel
|
||||||
|
}}
|
||||||
|
placement={"topLeft"}
|
||||||
|
trigger={["click"]}>
|
||||||
|
<Tooltip title={t("selectAModel")}>
|
||||||
|
<button type="button" className="dark:text-gray-300">
|
||||||
|
<LucideBrain className="h-5 w-5"/>
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
</Dropdown>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -63,13 +63,18 @@ export default function OptionLayout({
|
|||||||
return prompts?.find((prompt) => prompt.id === id)
|
return prompts?.find((prompt) => prompt.id === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePromptChange = (value: string) => {
|
const handlePromptChange = (value?: string) => {
|
||||||
|
if (!value) {
|
||||||
|
setSelectedSystemPrompt(undefined)
|
||||||
|
setSelectedQuickPrompt(undefined)
|
||||||
|
return
|
||||||
|
}
|
||||||
const prompt = getPromptInfoById(value)
|
const prompt = getPromptInfoById(value)
|
||||||
if (prompt?.is_system) {
|
if (prompt?.is_system) {
|
||||||
setSelectedSystemPrompt(prompt.id)
|
setSelectedSystemPrompt(prompt.id)
|
||||||
} else {
|
} else {
|
||||||
|
setSelectedSystemPrompt(undefined)
|
||||||
setSelectedQuickPrompt(prompt!.content)
|
setSelectedQuickPrompt(prompt!.content)
|
||||||
setSelectedSystemPrompt("")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import { useTranslation } from "react-i18next"
|
|||||||
import { Link, useLocation } from "react-router-dom"
|
import { Link, useLocation } from "react-router-dom"
|
||||||
import { OllamaIcon } from "../Icons/Ollama"
|
import { OllamaIcon } from "../Icons/Ollama"
|
||||||
import { Tag } from "antd"
|
import { Tag } from "antd"
|
||||||
|
import { BetaTag } from "../Common/Beta"
|
||||||
|
|
||||||
function classNames(...classes: string[]) {
|
function classNames(...classes: string[]) {
|
||||||
return classes.filter(Boolean).join(" ")
|
return classes.filter(Boolean).join(" ")
|
||||||
@ -81,7 +82,7 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
name={
|
name={
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
{t("manageKnowledge.title")}
|
{t("manageKnowledge.title")}
|
||||||
<Tag color="yellow">{t("common:beta")}</Tag>
|
<BetaTag />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
icon={BlocksIcon}
|
icon={BlocksIcon}
|
||||||
|
@ -9,6 +9,11 @@ import { SearchModeSettings } from "./search-mode"
|
|||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { useI18n } from "@/hooks/useI18n"
|
import { useI18n } from "@/hooks/useI18n"
|
||||||
import { TTSModeSettings } from "./tts-mode"
|
import { TTSModeSettings } from "./tts-mode"
|
||||||
|
import {
|
||||||
|
exportPageAssistData,
|
||||||
|
importPageAssistData
|
||||||
|
} from "@/libs/export-import"
|
||||||
|
import { BetaTag } from "@/components/Common/Beta"
|
||||||
|
|
||||||
export const SettingOther = () => {
|
export const SettingOther = () => {
|
||||||
const { clearChat, speechToTextLanguage, setSpeechToTextLanguage } =
|
const { clearChat, speechToTextLanguage, setSpeechToTextLanguage } =
|
||||||
@ -98,7 +103,7 @@ export const SettingOther = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div>
|
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div>
|
||||||
</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 ">
|
<span className="text-gray-500 dark:text-neutral-50 ">
|
||||||
{t("generalSettings.system.deleteChatHistory.label")}
|
{t("generalSettings.system.deleteChatHistory.label")}
|
||||||
</span>
|
</span>
|
||||||
@ -122,6 +127,37 @@ export const SettingOther = () => {
|
|||||||
{t("generalSettings.system.deleteChatHistory.button")}
|
{t("generalSettings.system.deleteChatHistory.button")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery, useQueryClient } from "@tanstack/react-query"
|
||||||
import { Select } from "antd"
|
import { Select } from "antd"
|
||||||
import { RotateCcw } from "lucide-react"
|
import { RotateCcw } from "lucide-react"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
@ -15,6 +15,7 @@ import {
|
|||||||
export const EmptySidePanel = () => {
|
export const EmptySidePanel = () => {
|
||||||
const [ollamaURL, setOllamaURL] = useState<string>("")
|
const [ollamaURL, setOllamaURL] = useState<string>("")
|
||||||
const { t } = useTranslation(["playground", "common"])
|
const { t } = useTranslation(["playground", "common"])
|
||||||
|
const queryClient = useQueryClient()
|
||||||
const {
|
const {
|
||||||
data: ollamaInfo,
|
data: ollamaInfo,
|
||||||
status: ollamaStatus,
|
status: ollamaStatus,
|
||||||
@ -26,7 +27,9 @@ export const EmptySidePanel = () => {
|
|||||||
const ollamaURL = await getOllamaURL()
|
const ollamaURL = await getOllamaURL()
|
||||||
const isOk = await isOllamaRunning()
|
const isOk = await isOllamaRunning()
|
||||||
const models = await fetchChatModels({ returnEmpty: false })
|
const models = await fetchChatModels({ returnEmpty: false })
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["getAllModelsForSelect"]
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
isOk,
|
isOk,
|
||||||
models,
|
models,
|
||||||
|
@ -10,6 +10,7 @@ import { useWebUI } from "~/store/webui"
|
|||||||
import { defaultEmbeddingModelForRag } from "~/services/ollama"
|
import { defaultEmbeddingModelForRag } from "~/services/ollama"
|
||||||
import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react"
|
import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { ModelSelect } from "@/components/Common/ModelSelect"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
dropedFile: File | undefined
|
dropedFile: File | undefined
|
||||||
@ -186,6 +187,7 @@ export const SidepanelForm = ({ dropedFile }: Props) => {
|
|||||||
{...form.getInputProps("message")}
|
{...form.getInputProps("message")}
|
||||||
/>
|
/>
|
||||||
<div className="flex mt-4 justify-end gap-3">
|
<div className="flex mt-4 justify-end gap-3">
|
||||||
|
<ModelSelect />
|
||||||
<Tooltip title={t("tooltip.speechToText")}>
|
<Tooltip title={t("tooltip.speechToText")}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -417,3 +417,42 @@ export const getUserId = async () => {
|
|||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exportChatHistory = async () => {
|
||||||
|
const db = new PageAssitDatabase()
|
||||||
|
const chatHistories = await db.getChatHistories()
|
||||||
|
const messages = await Promise.all(
|
||||||
|
chatHistories.map(async (history) => {
|
||||||
|
const messages = await db.getChatHistory(history.id)
|
||||||
|
return { history, messages }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return messages
|
||||||
|
}
|
||||||
|
|
||||||
|
export const importChatHistory = async (
|
||||||
|
data: {
|
||||||
|
history: HistoryInfo
|
||||||
|
messages: MessageHistory
|
||||||
|
}[]
|
||||||
|
) => {
|
||||||
|
const db = new PageAssitDatabase()
|
||||||
|
for (const { history, messages } of data) {
|
||||||
|
await db.addChatHistory(history)
|
||||||
|
for (const message of messages) {
|
||||||
|
await db.addMessage(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -190,3 +190,16 @@ export const deleteSource = async (id: string, source_id: string) => {
|
|||||||
await db.deleteSource(id, source_id)
|
await db.deleteSource(id, source_id)
|
||||||
await deleteVectorByFileId(`vector:${id}`, source_id)
|
await deleteVectorByFileId(`vector:${id}`, source_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exportKnowledge = async () => {
|
||||||
|
const db = new PageAssistKnowledge()
|
||||||
|
const data = await db.getAll()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
export const importKnowledge = async (data: Knowledge[]) => {
|
||||||
|
const db = new PageAssistKnowledge()
|
||||||
|
for (const d of data) {
|
||||||
|
await db.create(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -100,6 +100,34 @@ export class PageAssistVectorDb {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAll = async (): Promise<VectorData[]> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.get(null, (result) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
reject(chrome.runtime.lastError)
|
||||||
|
} else {
|
||||||
|
resolve(Object.values(result))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
export const insertVector = async (
|
||||||
@ -127,3 +155,14 @@ export const deleteVectorByFileId = async (
|
|||||||
const db = new PageAssistVectorDb()
|
const db = new PageAssistVectorDb()
|
||||||
return db.deleteVectorByFileId(id, file_id)
|
return db.deleteVectorByFileId(id, file_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exportVectors = async () => {
|
||||||
|
const db = new PageAssistVectorDb()
|
||||||
|
const data = await db.getAll()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
export const importVectors = async (data: VectorData[]) => {
|
||||||
|
const db = new PageAssistVectorDb()
|
||||||
|
return db.saveImportedData(data)
|
||||||
|
}
|
||||||
|
@ -235,7 +235,7 @@ export const useMessage = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1) + "▋"
|
message: fullText + "▋"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
@ -431,7 +431,7 @@ export const useMessage = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1) + "▋"
|
message: fullText + "▋"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
@ -445,7 +445,7 @@ export const useMessage = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1)
|
message: fullText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
|
@ -230,7 +230,7 @@ export const useMessageOption = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1) + "▋"
|
message: fullText + "▋"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
@ -436,7 +436,7 @@ export const useMessageOption = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1) + "▋"
|
message: fullText + "▋"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
@ -450,7 +450,7 @@ export const useMessageOption = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1)
|
message: fullText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
@ -646,7 +646,7 @@ export const useMessageOption = () => {
|
|||||||
if (message.id === generateMessageId) {
|
if (message.id === generateMessageId) {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText.slice(0, -1) + "▋"
|
message: fullText + "▋"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
|
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)
|
||||||
|
}
|
@ -24,7 +24,7 @@ export default defineConfig({
|
|||||||
srcDir: "src",
|
srcDir: "src",
|
||||||
outDir: "build",
|
outDir: "build",
|
||||||
manifest: {
|
manifest: {
|
||||||
version: "1.1.5",
|
version: "1.1.6",
|
||||||
name: '__MSG_extName__',
|
name: '__MSG_extName__',
|
||||||
description: '__MSG_extDescription__',
|
description: '__MSG_extDescription__',
|
||||||
default_locale: 'en',
|
default_locale: 'en',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user