diff --git a/bun.lockb b/bun.lockb index ce5cb65..a4deaa6 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index d9a126b..98f5370 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "langchain": "^0.1.28", "lucide-react": "^0.350.0", "ml-distance": "^4.0.1", - "pdfjs-dist": "^4.0.379", + "pdfjs-dist": "4.0.379", "property-information": "^6.4.1", "pubsub-js": "^1.9.4", "react": "18.2.0", 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/Common/ModelSelect.tsx b/src/components/Common/ModelSelect.tsx new file mode 100644 index 0000000..22160b8 --- /dev/null +++ b/src/components/Common/ModelSelect.tsx @@ -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 && ( + ({ + key: d.name, + label: ( +
+
+ +
+ {d.name} +
+ ), + 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"]}> + + + +
+ )} + + ) +} diff --git a/src/components/Layouts/Layout.tsx b/src/components/Layouts/Layout.tsx index 296c641..03916be 100644 --- a/src/components/Layouts/Layout.tsx +++ b/src/components/Layouts/Layout.tsx @@ -63,13 +63,18 @@ export default function OptionLayout({ 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) if (prompt?.is_system) { setSelectedSystemPrompt(prompt.id) } else { + setSelectedSystemPrompt(undefined) setSelectedQuickPrompt(prompt!.content) - setSelectedSystemPrompt("") } } 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/components/Sidepanel/Chat/empty.tsx b/src/components/Sidepanel/Chat/empty.tsx index 41305b8..499e320 100644 --- a/src/components/Sidepanel/Chat/empty.tsx +++ b/src/components/Sidepanel/Chat/empty.tsx @@ -1,4 +1,4 @@ -import { useQuery } from "@tanstack/react-query" +import { useQuery, useQueryClient } from "@tanstack/react-query" import { Select } from "antd" import { RotateCcw } from "lucide-react" import { useEffect, useState } from "react" @@ -15,6 +15,7 @@ import { export const EmptySidePanel = () => { const [ollamaURL, setOllamaURL] = useState("") const { t } = useTranslation(["playground", "common"]) + const queryClient = useQueryClient() const { data: ollamaInfo, status: ollamaStatus, @@ -26,7 +27,9 @@ export const EmptySidePanel = () => { const ollamaURL = await getOllamaURL() const isOk = await isOllamaRunning() const models = await fetchChatModels({ returnEmpty: false }) - + queryClient.invalidateQueries({ + queryKey: ["getAllModelsForSelect"] + }) return { isOk, models, diff --git a/src/components/Sidepanel/Chat/form.tsx b/src/components/Sidepanel/Chat/form.tsx index b8b3fc9..45ec340 100644 --- a/src/components/Sidepanel/Chat/form.tsx +++ b/src/components/Sidepanel/Chat/form.tsx @@ -10,6 +10,7 @@ import { useWebUI } from "~/store/webui" import { defaultEmbeddingModelForRag } from "~/services/ollama" import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react" import { useTranslation } from "react-i18next" +import { ModelSelect } from "@/components/Common/ModelSelect" type Props = { dropedFile: File | undefined @@ -186,6 +187,7 @@ export const SidepanelForm = ({ dropedFile }: Props) => { {...form.getInputProps("message")} />
+