diff --git a/src/assets/locale/da/settings.json b/src/assets/locale/da/settings.json
index 1d088d1..37168c4 100644
--- a/src/assets/locale/da/settings.json
+++ b/src/assets/locale/da/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Genoptag den sidste chat, når du åbner SidePanel (copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Genoptag den sidste chat, når du åbner Web UI'en"
+ },
"hideCurrentChatModelSettings": {
"label": "Skjul nuværende chat model indstillinger"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Besøg websitet nævnt i samtalen"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/de/settings.json b/src/assets/locale/de/settings.json
index c6b134b..6315f85 100644
--- a/src/assets/locale/de/settings.json
+++ b/src/assets/locale/de/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Letzten Chat beim Öffnen des Seitenpanels fortsetzen (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Letzten Chat beim Öffnen der Web-UI fortsetzen"
+ },
"hideCurrentChatModelSettings": {
"label": "Aktuelle Chat-Modell-Einstellungen ausblenden"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Die in der Nachricht erwähnte Website besuchen"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG-URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/en/common.json b/src/assets/locale/en/common.json
index d033144..88c1be5 100644
--- a/src/assets/locale/en/common.json
+++ b/src/assets/locale/en/common.json
@@ -87,6 +87,9 @@
"label": "Top P",
"placeholder": "Enter Top P value (e.g. 0.9, 0.95)"
},
+ "useMMap": {
+ "label": "useMmap"
+ },
"numGpu": {
"label": "Num GPU",
"placeholder": "Enter number of layers to send to GPU(s)"
diff --git a/src/assets/locale/en/settings.json b/src/assets/locale/en/settings.json
index eb98bf4..f0498df 100644
--- a/src/assets/locale/en/settings.json
+++ b/src/assets/locale/en/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Resume the last chat when opening the SidePanel (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Resume the last chat when opening the Web UI"
+ },
"hideCurrentChatModelSettings": {
"label": "Hide the current Chat Model Settings"
},
@@ -33,8 +36,8 @@
"generateTitle": {
"label": "Generate Title using AI"
},
- "ollamaStatus" :{
- "label":"Enable or disable Ollama connection status check"
+ "ollamaStatus": {
+ "label": "Enable or disable Ollama connection status check"
}
},
"sidepanelRag": {
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Visit the website mentioned in the message"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/es/settings.json b/src/assets/locale/es/settings.json
index 4ed17d8..eb98d80 100644
--- a/src/assets/locale/es/settings.json
+++ b/src/assets/locale/es/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Retomar el último chat al abrir el Panel Lateral (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Retomar el último chat al abrir la Interfaz Web"
+ },
"hideCurrentChatModelSettings": {
"label": "Ocultar Configuraciones del Modelo de Chat Actual"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Visita el sitio web mencionado en el mensaje"
+ },
+ "searxng": {
+ "url": {
+ "label": "URL de SearXNG"
+ }
}
},
"system": {
diff --git a/src/assets/locale/fa/settings.json b/src/assets/locale/fa/settings.json
index 0a0cde8..985639a 100644
--- a/src/assets/locale/fa/settings.json
+++ b/src/assets/locale/fa/settings.json
@@ -62,6 +62,11 @@
},
"visitSpecificWebsite": {
"label": "مراجعه به وب سایت ذکر شده در پیام"
+ },
+ "searxng": {
+ "url": {
+ "label": "آدرس SearXNG"
+ }
}
},
"system": {
diff --git a/src/assets/locale/fr/settings.json b/src/assets/locale/fr/settings.json
index 7d3b191..3ef9b49 100644
--- a/src/assets/locale/fr/settings.json
+++ b/src/assets/locale/fr/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Reprendre la dernière conversation lors de l'ouverture du sidepanel (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Reprendre la dernière conversation lors de l'ouverture de l'interface Web"
+ },
"hideCurrentChatModelSettings": {
"label": "Masquer les paramètres actuels du modèle de chat"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Visitez le site web mentionné dans le message"
+ },
+ "searxng": {
+ "url": {
+ "label": "URL SearXNG"
+ }
}
},
"system": {
diff --git a/src/assets/locale/it/settings.json b/src/assets/locale/it/settings.json
index e227d22..4e07754 100644
--- a/src/assets/locale/it/settings.json
+++ b/src/assets/locale/it/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Riprendi l'ultima chat quando apri il Pannello Laterale (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Riprendi l'ultima chat quando apri l'interfaccia Web"
+ },
"hideCurrentChatModelSettings": {
"label": "Nascondi le impostazioni correnti del modello Chat"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Visita il sito web menzionato nel messaggio"
+ },
+ "searxng": {
+ "url": {
+ "label": "URL SearXNG"
+ }
}
},
"system": {
diff --git a/src/assets/locale/ja-JP/settings.json b/src/assets/locale/ja-JP/settings.json
index 0058062..d34b63b 100644
--- a/src/assets/locale/ja-JP/settings.json
+++ b/src/assets/locale/ja-JP/settings.json
@@ -24,6 +24,9 @@
"copilotResumeLastChat": {
"label": "サイドパネルを開いたときに最後のチャットを再開 (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Web UIを開いたときに最後のチャットを再開"
+ },
"hideCurrentChatModelSettings": {
"label": "現在のチャットモデル設定を非表示"
},
@@ -65,6 +68,11 @@
},
"visitSpecificWebsite": {
"label": "メッセージに記載されたウェブサイトを訪問してください"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/ko/settings.json b/src/assets/locale/ko/settings.json
index f3c7109..73ac857 100644
--- a/src/assets/locale/ko/settings.json
+++ b/src/assets/locale/ko/settings.json
@@ -24,6 +24,9 @@
"copilotResumeLastChat": {
"label": "사이드 패널을 열 때 마지막 채팅 재개 (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "웹 UI를 열 때 마지막 채팅 재개"
+ },
"hideCurrentChatModelSettings": {
"label": "현재 채팅 모델 설정 숨기기"
},
@@ -65,6 +68,11 @@
},
"visitSpecificWebsite": {
"label": "메시지에 언급된 웹사이트 방문"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/ml/settings.json b/src/assets/locale/ml/settings.json
index 03d67f1..b9ccb0d 100644
--- a/src/assets/locale/ml/settings.json
+++ b/src/assets/locale/ml/settings.json
@@ -24,6 +24,9 @@
"copilotResumeLastChat": {
"label": "സൈഡ്പാനൽ തുറക്കുമ്പോൾ അവസാനത്തെ ചാറ്റ് പുനരാരംഭിക്കുക (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "വെബ് UI തുറക്കുമ്പോൾ അവസാനത്തെ ചാറ്റ് പുനരാരംഭിക്കുക"
+ },
"hideCurrentChatModelSettings": {
"label": "നിലവിലുള്ള ചാറ്റ് മോഡൽ ക്രമീകരണങ്ങൾ മറയ്ക്കുക"
},
@@ -65,6 +68,11 @@
},
"visitSpecificWebsite": {
"label": "സന്ദേശത്തിൽ പറയുന്ന വെബ്സൈറ്റ് സന്ദർശിക്കുക."
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/no/settings.json b/src/assets/locale/no/settings.json
index 8085e3e..c73cbec 100644
--- a/src/assets/locale/no/settings.json
+++ b/src/assets/locale/no/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Gjenoppta siste chat ved åpning av SidePanel (copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Gjenoppta siste chat når Web UI åpnes"
+ },
"hideCurrentChatModelSettings": {
"label": "Skjul gjeldende chat modell innstillinger"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Besøk nettstedet nevnt i samtalen"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
@@ -241,25 +249,104 @@
},
"ollamaSettings": {
"title": "Ollama Innstillinger",
- "heading": "Konfigurer Ollama Plugin",
- "enabled": {
- "label": "Aktiver Ollama Plugin"
- },
- "provider": {
- "label": "Ollama Tilbyder",
- "placeholder": "Velg en Ollama tilbyder"
- },
- "apiKey": {
- "label": "Ollama API Nøkkel",
- "placeholder": "Skriv inn Ollama API Nøkkel",
- "required": "API Nøkkel er påkrevd"
- },
- "saveBtn": {
- "save": "Lagre"
- },
- "notification": {
- "saveSuccess": "Ollama Plugin lagret vellykket",
- "someError": "Noe gikk galt. Vennligst prøv igjen senere"
+ "heading": "Konfigurer Ollama",
+ "settings": {
+ "ollamaUrl": {
+ "label": "Ollama URL",
+ "placeholder": "Skriv inn Ollama URL"
+ },
+ "advanced": {
+ "label": "Avansert Ollama URL-konfigurasjon",
+ "urlRewriteEnabled": {
+ "label": "Aktiver eller deaktiver tilpasset opprinnelses-URL"
+ },
+ "rewriteUrl": {
+ "label": "Tilpasset opprinnelses-URL",
+ "placeholder": "Skriv inn tilpasset opprinnelses-URL"
+ },
+ "headers": {
+ "label": "Tilpass Headers",
+ "LeggTil": "Legg til Header",
+ "key": {
+ "label": "Header Nøkkel",
+ "placeholder": "Autorisasjon"
+ },
+ "value": {
+ "label": "Header Verdi",
+ "placeholder": "Bearer token"
+ }
+ },
+ "help": "Hvis du har forbindelsesproblemer med Ollama på Page Assist, kan du konfigurere en brukerdefinert opprinnelses-URL. For mer informasjon om konfigurasjonen, klikk her."
+ }
}
+ },
+ "manageSearch": {
+ "title": "Administrer Web Søk",
+ "heading": "Konfigurer Web Søk"
+ },
+ "about": {
+ "title": "Om",
+ "heading": "Om",
+ "chromeVersion": "Page Assist Versjon",
+ "ollamaVersion": "Ollama Versjon",
+ "support": "Du kan støtte Page Assist-prosjektet ved å donere eller sponse via følgende plattformer:",
+ "koFi": "Støtt på Ko-fi",
+ "githubSponsor": "Spons på GitHub",
+ "githubRepo": "GitHub Repository"
+ },
+ "manageKnowledge": {
+ "title": "Administrer Kunnskap",
+ "heading": "Konfigurer Kunnskapsbase"
+ },
+ "rag": {
+ "title": "RAG Innstillinger",
+ "ragSettings": {
+ "label": "RAG Innstillinger",
+ "model": {
+ "label": "Embedding Modell",
+ "required": "Vennligst velg en modell",
+ "help": "Det anbefales sterkt å bruke embeddingsmodeller som `nomic-embed-text`.",
+ "placeholder": "Velg en modell"
+ },
+ "chunkSize": {
+ "label": "Delstørrelse",
+ "placeholder": "Skriv inn delstørrelse",
+ "required": "Vennligst skriv inn en delstørrelse"
+ },
+ "chunkOverlap": {
+ "label": "Deloverlapp",
+ "placeholder": "Skriv inn deloverlapp",
+ "required": "Vennligst skriv inn deloverlapp"
+ },
+ "totalFilePerKB": {
+ "label": "Kunnskapsbase standard filopplastingsgrense",
+ "placeholder": "Skriv inn standard filopplastingsgrense (f.eks. 10)",
+ "required": "Vennligst skriv inn standard filopplastingsgrense"
+ },
+ "noOfRetrievedDocs": {
+ "label": "Antall hentede dokumenter",
+ "placeholder": "Skriv inn antall hentede dokumenter",
+ "required": "Vennligst skriv inn antall hentede dokumenter"
+ }
+ },
+ "prompt": {
+ "label": "Konfigurer RAG Prompt",
+ "option1": "Normal",
+ "option2": "Web",
+ "alert": "Konfigurering av systemprompt her er foreldet. Vennligst bruk Administrer Prompts-seksjonen for å legge til eller endre prompts. Denne seksjonen vil bli fjernet i fremtidige versjoner.",
+ "systemPrompt": "Systemprompt",
+ "systemPromptPlaceholder": "Skriv inn systemprompt",
+ "webSearchPrompt": "Websøke-prompt",
+ "webSearchPromptHelp": "Ikke fjern `{search_results}` fra prompten.",
+ "webSearchPromptError": "Vennligst skriv inn en websøke-prompt",
+ "webSearchPromptPlaceholder": "Skriv inn websøke-prompt",
+ "webSearchFollowUpPrompt": "Oppfølgingsprompt for websøking",
+ "webSearchFollowUpPromptHelp": "Ikke fjern `{chat_history}` og `{question}` fra prompten.",
+ "webSearchFollowUpPromptError": "Vennligst skriv inn din oppfølgingsprompt for websøking!",
+ "webSearchFollowUpPromptPlaceholder": "Din oppfølgingsprompt for websøking"
+ }
+ },
+ "chromeAiSettings": {
+ "title": "Chrome AI Innstillinger"
}
}
diff --git a/src/assets/locale/pt-BR/settings.json b/src/assets/locale/pt-BR/settings.json
index fad3b11..019ad68 100644
--- a/src/assets/locale/pt-BR/settings.json
+++ b/src/assets/locale/pt-BR/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Retomar o último chat ao abrir o Painel Lateral (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Retomar o último chat ao abrir a Interface Web"
+ },
"hideCurrentChatModelSettings": {
"label": "Ocultar as Configurações Atuais do Modelo de Chat"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Visitar o site mencionado na mensagem"
+ },
+ "searxng": {
+ "url": {
+ "label": "URL do SearXNG"
+ }
}
},
"system": {
diff --git a/src/assets/locale/ru/settings.json b/src/assets/locale/ru/settings.json
index adf0008..7e6b75b 100644
--- a/src/assets/locale/ru/settings.json
+++ b/src/assets/locale/ru/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Возобновить последний чат при открытии боковой панели (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Возобновить последний чат при открытии веб-интерфейса"
+ },
"hideCurrentChatModelSettings": {
"label": "Скрыть текущие настройки модели чата"
},
@@ -63,6 +66,11 @@
},
"visitSpecificWebsite": {
"label": "Посетите веб-сайт, указанный в сообщении."
+ },
+ "searxng": {
+ "url": {
+ "label": "URL-адрес SearXNG"
+ }
}
},
"system": {
diff --git a/src/assets/locale/sv/settings.json b/src/assets/locale/sv/settings.json
index d1e11d0..3edaa52 100644
--- a/src/assets/locale/sv/settings.json
+++ b/src/assets/locale/sv/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Återuppta den senaste chatten när du öppnar sidopanelen (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Återuppta den senaste chatten när du öppnar webbgränssnittet"
+ },
"hideCurrentChatModelSettings": {
"label": "Göm de nuvarande chattmodellinställningarna"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Besök webbplatsen som nämns i meddelandet"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL"
+ }
}
},
"system": {
diff --git a/src/assets/locale/uk/settings.json b/src/assets/locale/uk/settings.json
index db0695b..91fe5de 100644
--- a/src/assets/locale/uk/settings.json
+++ b/src/assets/locale/uk/settings.json
@@ -21,6 +21,9 @@
"copilotResumeLastChat": {
"label": "Поновити останню розмову при відкритті бічної панелі (Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "Поновити останню розмову при відкритті веб-інтерфейсу"
+ },
"hideCurrentChatModelSettings": {
"label": "Приховати налаштування поточної моделі чату"
},
@@ -62,6 +65,11 @@
},
"visitSpecificWebsite": {
"label": "Відвідати веб-сайт, згаданий у повідомленні"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG URL-адреса"
+ }
}
},
"system": {
diff --git a/src/assets/locale/zh/settings.json b/src/assets/locale/zh/settings.json
index 2f834e9..83c576d 100644
--- a/src/assets/locale/zh/settings.json
+++ b/src/assets/locale/zh/settings.json
@@ -24,6 +24,9 @@
"copilotResumeLastChat": {
"label": "打开侧边栏时恢复上次聊天(Copilot)"
},
+ "webUIResumeLastChat": {
+ "label": "打开Web UI时恢复上次聊天"
+ },
"hideCurrentChatModelSettings": {
"label": "隐藏当前聊天模型设置"
},
@@ -65,6 +68,11 @@
},
"visitSpecificWebsite": {
"label": "访问消息中提到的网站。"
+ },
+ "searxng": {
+ "url": {
+ "label": "SearXNG 网址"
+ }
}
},
"system": {
diff --git a/src/components/Common/Settings/CurrentChatModelSettings.tsx b/src/components/Common/Settings/CurrentChatModelSettings.tsx
index e950bd9..b1218b4 100644
--- a/src/components/Common/Settings/CurrentChatModelSettings.tsx
+++ b/src/components/Common/Settings/CurrentChatModelSettings.tsx
@@ -5,15 +5,19 @@ import { useStoreChatModelSettings } from "@/store/model"
import { useQuery } from "@tanstack/react-query"
import {
Collapse,
+ Divider,
Drawer,
Form,
Input,
InputNumber,
Modal,
- Skeleton
+ Skeleton,
+ Switch,
+ Button
} from "antd"
-import React from "react"
+import React, { useState, useCallback } from "react"
import { useTranslation } from "react-i18next"
+import { SaveButton } from "../SaveButton"
type Props = {
open: boolean
@@ -30,12 +34,31 @@ export const CurrentChatModelSettings = ({
const [form] = Form.useForm()
const cUserSettings = useStoreChatModelSettings()
const { selectedSystemPrompt } = useMessageOption()
+
+ const savePrompt = useCallback(
+ (value: string) => {
+ cUserSettings.setX("systemPrompt", value)
+ },
+ [cUserSettings]
+ )
+
+ const saveSettings = useCallback(
+ (values: any) => {
+ Object.entries(values).forEach(([key, value]) => {
+ if (key !== "systemPrompt") {
+ cUserSettings.setX(key, value)
+ }
+ })
+ },
+ [cUserSettings]
+ )
+
const { isPending: isLoading } = useQuery({
queryKey: ["fetchModelConfig2", open],
queryFn: async () => {
const data = await getAllModelSettings()
- let tempSystemPrompt = "";
+ let tempSystemPrompt = ""
// i hate this method but i need this feature so badly that i need to do this
if (selectedSystemPrompt) {
@@ -52,7 +75,8 @@ export const CurrentChatModelSettings = ({
seed: cUserSettings.seed,
numGpu: cUserSettings.numGpu ?? data.numGpu,
numPredict: cUserSettings.numPredict ?? data.numPredict,
- systemPrompt: cUserSettings.systemPrompt ?? tempSystemPrompt
+ systemPrompt: cUserSettings.systemPrompt ?? tempSystemPrompt,
+ useMMap: cUserSettings.useMMap ?? data.useMMap
})
return data
},
@@ -61,25 +85,17 @@ export const CurrentChatModelSettings = ({
refetchOnWindowFocus: false
})
-
const renderBody = () => {
return (
<>
{!isLoading ? (
savePrompt(e.target.value)}
/>
+
>
)}
+
+
@@ -139,6 +159,8 @@ export const CurrentChatModelSettings = ({
/>
+
+
+
+
+
+
)
}
]}
/>
-
-
+
) : (
diff --git a/src/components/Option/Playground/Playground.tsx b/src/components/Option/Playground/Playground.tsx
index bc52b59..b97dae9 100644
--- a/src/components/Option/Playground/Playground.tsx
+++ b/src/components/Option/Playground/Playground.tsx
@@ -2,11 +2,18 @@ import React from "react"
import { PlaygroundForm } from "./PlaygroundForm"
import { PlaygroundChat } from "./PlaygroundChat"
import { useMessageOption } from "@/hooks/useMessageOption"
+import { webUIResumeLastChat } from "@/services/app"
+import {
+ formatToChatHistory,
+ formatToMessage,
+ getRecentChatFromWebUI
+} from "@/db"
export const Playground = () => {
const drop = React.useRef(null)
const [dropedFile, setDropedFile] = React.useState()
- const { selectedKnowledge } = useMessageOption()
+ const { selectedKnowledge, messages, setHistoryId, setHistory, setMessages } =
+ useMessageOption()
const [dropState, setDropState] = React.useState<
"idle" | "dragging" | "error"
@@ -71,6 +78,26 @@ export const Playground = () => {
}
}
}, [selectedKnowledge])
+
+ const setRecentMessagesOnLoad = async () => {
+ const isEnabled = await webUIResumeLastChat()
+ if (!isEnabled) {
+ return
+ }
+ if (messages.length === 0) {
+ const recentChat = await getRecentChatFromWebUI()
+ if (recentChat) {
+ setHistoryId(recentChat.history.id)
+ setHistory(formatToChatHistory(recentChat.messages))
+ setMessages(formatToMessage(recentChat.messages))
+ }
+ }
+ }
+
+ React.useEffect(() => {
+ setRecentMessagesOnLoad()
+ }, [])
+
return (
{
dropState === "dragging" ? "bg-gray-100 dark:bg-gray-800 z-10" : ""
} bg-white dark:bg-[#171717]`}>
-
+
diff --git a/src/components/Option/Playground/PlaygroundEmpty.tsx b/src/components/Option/Playground/PlaygroundEmpty.tsx
index 4e23d7d..0b772f6 100644
--- a/src/components/Option/Playground/PlaygroundEmpty.tsx
+++ b/src/components/Option/Playground/PlaygroundEmpty.tsx
@@ -39,6 +39,13 @@ export const PlaygroundEmpty = () => {
enabled: checkOllamaStatus
})
+ useEffect(() => {
+ if (ollamaInfo?.ollamaURL) {
+ setOllamaURL(ollamaInfo.ollamaURL)
+ }
+ }, [ollamaInfo])
+
+
if (!checkOllamaStatus) {
return (
diff --git a/src/components/Option/Settings/general-settings.tsx b/src/components/Option/Settings/general-settings.tsx
index f615236..c471fd4 100644
--- a/src/components/Option/Settings/general-settings.tsx
+++ b/src/components/Option/Settings/general-settings.tsx
@@ -27,6 +27,11 @@ export const GeneralSettings = () => {
false
)
+ const [webUIResumeLastChat, setWebUIResumeLastChat] = useStorage(
+ "webUIResumeLastChat",
+ false
+ )
+
const [restoreLastChatModel, setRestoreLastChatModel] = useStorage(
"restoreLastChatModel",
false
@@ -113,6 +118,17 @@ export const GeneralSettings = () => {
onChange={(checked) => setCopilotResumeLastChat(checked)}
/>
+
+
+
+ {t("generalSettings.settings.webUIResumeLastChat.label")}
+
+
+
setWebUIResumeLastChat(checked)}
+ />
+
diff --git a/src/components/Option/Settings/model-settings.tsx b/src/components/Option/Settings/model-settings.tsx
index 40523f7..18015ba 100644
--- a/src/components/Option/Settings/model-settings.tsx
+++ b/src/components/Option/Settings/model-settings.tsx
@@ -2,7 +2,7 @@ import { BetaTag } from "@/components/Common/Beta"
import { SaveButton } from "@/components/Common/SaveButton"
import { getAllModelSettings, setModelSetting } from "@/services/model-settings"
import { useQuery, useQueryClient } from "@tanstack/react-query"
-import { Form, Skeleton, Input, InputNumber, Collapse } from "antd"
+import { Form, Skeleton, Input, InputNumber, Collapse, Switch } from "antd"
import React from "react"
import { useTranslation } from "react-i18next"
@@ -78,13 +78,13 @@ export const ModelSettings = () => {
/>
-
-
+ name="numPredict"
+ label={t("modelSettings.form.numPredict.label")}>
+
+
{
+
+
+
)
}
diff --git a/src/components/Option/Settings/search-mode.tsx b/src/components/Option/Settings/search-mode.tsx
index 53f391b..69ae112 100644
--- a/src/components/Option/Settings/search-mode.tsx
+++ b/src/components/Option/Settings/search-mode.tsx
@@ -3,7 +3,7 @@ import { getSearchSettings, setSearchSettings } from "@/services/search"
import { SUPPORTED_SERACH_PROVIDERS } from "@/utils/search-provider"
import { useForm } from "@mantine/form"
import { useQuery, useQueryClient } from "@tanstack/react-query"
-import { Select, Skeleton, Switch, InputNumber } from "antd"
+import { Select, Skeleton, Switch, InputNumber, Input } from "antd"
import { useTranslation } from "react-i18next"
export const SearchModeSettings = () => {
@@ -14,7 +14,9 @@ export const SearchModeSettings = () => {
isSimpleInternetSearch: false,
searchProvider: "",
totalSearchResults: 0,
- visitSpecificWebsite: false
+ visitSpecificWebsite: false,
+ searxngURL: "",
+ searxngJSONMode: false
}
})
@@ -62,6 +64,23 @@ export const SearchModeSettings = () => {
/>
+ {form.values.searchProvider === "searxng" && (
+ <>
+
+
+ {t("generalSettings.webSearch.searxng.url.label")}
+
+
+
+
+
+ >
+ )}
{t("generalSettings.webSearch.searchMode.label")}
diff --git a/src/db/index.ts b/src/db/index.ts
index da837b2..6cab3ef 100644
--- a/src/db/index.ts
+++ b/src/db/index.ts
@@ -356,11 +356,11 @@ export const updateMessageByIndex = async (
message: string
) => {
try {
- const db = new PageAssitDatabase()
- const chatHistory = (await db.getChatHistory(history_id)).reverse()
- chatHistory[index].content = message
- await db.db.set({ [history_id]: chatHistory.reverse() })
- } catch(e) {
+ const db = new PageAssitDatabase()
+ const chatHistory = (await db.getChatHistory(history_id)).reverse()
+ chatHistory[index].content = message
+ await db.db.set({ [history_id]: chatHistory.reverse() })
+ } catch (e) {
// temp chat will break
}
}
@@ -515,6 +515,20 @@ export const getRecentChatFromCopilot = async () => {
return { history, messages }
}
+export const getRecentChatFromWebUI = async () => {
+ const db = new PageAssitDatabase()
+ const chatHistories = await db.getChatHistories()
+ if (chatHistories.length === 0) return null
+ const history = chatHistories.find(
+ (history) => history.message_source === "web-ui"
+ )
+ if (!history) return null
+
+ const messages = await db.getChatHistory(history.id)
+
+ return { history, messages }
+}
+
export const getTitleById = async (id: string) => {
const db = new PageAssitDatabase()
const title = await db.getChatHistoryTitleById(id)
diff --git a/src/hooks/useMessage.tsx b/src/hooks/useMessage.tsx
index eb17f3e..c95554d 100644
--- a/src/hooks/useMessage.tsx
+++ b/src/hooks/useMessage.tsx
@@ -139,7 +139,9 @@ export const useMessage = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -271,7 +273,10 @@ export const useMessage = () => {
userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ??
+ userDefaultModelSettings?.useMMap
})
const response = await questionOllama.invoke(promptForQuestion)
query = response.content.toString()
@@ -482,7 +487,9 @@ export const useMessage = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -526,7 +533,7 @@ export const useMessage = () => {
const prompt = await systemPromptForNonRag()
const selectedPrompt = await getPromptById(selectedSystemPrompt)
- const applicationChatHistory = generateHistory(history, selectedModel)
+ const applicationChatHistory = []
const data = await getScreenshotFromCurrentTab()
console.log(
@@ -716,7 +723,9 @@ export const useMessage = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -944,7 +953,9 @@ export const useMessage = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -1023,7 +1034,10 @@ export const useMessage = () => {
userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ??
+ userDefaultModelSettings?.useMMap
})
const response = await questionOllama.invoke(promptForQuestion)
query = response.content.toString()
@@ -1211,7 +1225,9 @@ export const useMessage = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
diff --git a/src/hooks/useMessageOption.tsx b/src/hooks/useMessageOption.tsx
index 322287c..d687344 100644
--- a/src/hooks/useMessageOption.tsx
+++ b/src/hooks/useMessageOption.tsx
@@ -130,7 +130,9 @@ export const useMessageOption = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -209,7 +211,10 @@ export const useMessageOption = () => {
userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ??
+ userDefaultModelSettings?.useMMap
})
const response = await questionOllama.invoke(promptForQuestion)
query = response.content.toString()
@@ -429,7 +434,9 @@ export const useMessageOption = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -667,7 +674,9 @@ export const useMessageOption = () => {
currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap
})
let newMessage: Message[] = []
@@ -762,7 +771,10 @@ export const useMessageOption = () => {
userDefaultModelSettings?.numGpu,
numPredict:
currentChatModelSettings?.numPredict ??
- userDefaultModelSettings?.numPredict
+ userDefaultModelSettings?.numPredict,
+ useMMap:
+ currentChatModelSettings?.useMMap ??
+ userDefaultModelSettings?.useMMap
})
const response = await questionOllama.invoke(promptForQuestion)
query = response.content.toString()
diff --git a/src/models/index.ts b/src/models/index.ts
index 135025f..3481d52 100644
--- a/src/models/index.ts
+++ b/src/models/index.ts
@@ -16,6 +16,7 @@ export const pageAssistModel = async ({
seed,
numGpu,
numPredict,
+ useMMap
}: {
model: string
baseUrl: string
@@ -27,6 +28,7 @@ export const pageAssistModel = async ({
seed?: number
numGpu?: number
numPredict?: number
+ useMMap?: boolean
}) => {
if (model === "chrome::gemini-nano::page-assist") {
@@ -73,7 +75,8 @@ export const pageAssistModel = async ({
seed,
model,
numGpu,
- numPredict
+ numPredict,
+ useMMap,
})
diff --git a/src/services/app.ts b/src/services/app.ts
index bbae388..647abab 100644
--- a/src/services/app.ts
+++ b/src/services/app.ts
@@ -39,6 +39,10 @@ export const copilotResumeLastChat = async () => {
return await storage.get("copilotResumeLastChat")
}
+export const webUIResumeLastChat = async () => {
+ return await storage.get("webUIResumeLastChat")
+}
+
export const defaultSidebarOpen = async () => {
const sidebarOpen = await storage.get("sidebarOpen")
if (!sidebarOpen || sidebarOpen === "") {
diff --git a/src/services/search.ts b/src/services/search.ts
index f548cfe..66fb5cf 100644
--- a/src/services/search.ts
+++ b/src/services/search.ts
@@ -62,20 +62,45 @@ export const setTotalSearchResults = async (totalSearchResults: number) => {
await storage.set("totalSearchResults", totalSearchResults.toString())
}
+export const getSearxngURL = async () => {
+ const searxngURL = await storage.get("searxngURL")
+ return searxngURL || ""
+}
+
+export const isSearxngJSONMode = async () => {
+ const searxngJSONMode = await storage.get("searxngJSONMode")
+ return searxngJSONMode ?? false
+}
+
+export const setSearxngJSONMode = async (searxngJSONMode: boolean) => {
+ await storage.set("searxngJSONMode", searxngJSONMode)
+}
+
+export const setSearxngURL = async (searxngURL: string) => {
+ await storage.set("searxngURL", searxngURL)
+}
+
export const getSearchSettings = async () => {
- const [isSimpleInternetSearch, searchProvider, totalSearchResult, visitSpecificWebsite] =
+ const [isSimpleInternetSearch, searchProvider, totalSearchResult, visitSpecificWebsite,
+ searxngURL,
+ searxngJSONMode
+ ] =
await Promise.all([
getIsSimpleInternetSearch(),
getSearchProvider(),
totalSearchResults(),
- getIsVisitSpecificWebsite()
+ getIsVisitSpecificWebsite(),
+ getSearxngURL(),
+ isSearxngJSONMode()
])
return {
isSimpleInternetSearch,
searchProvider,
totalSearchResults: totalSearchResult,
- visitSpecificWebsite
+ visitSpecificWebsite,
+ searxngURL,
+ searxngJSONMode
}
}
@@ -83,17 +108,23 @@ export const setSearchSettings = async ({
isSimpleInternetSearch,
searchProvider,
totalSearchResults,
- visitSpecificWebsite
+ visitSpecificWebsite,
+ searxngJSONMode,
+ searxngURL
}: {
isSimpleInternetSearch: boolean
searchProvider: string
totalSearchResults: number
visitSpecificWebsite: boolean
+ searxngURL: string
+ searxngJSONMode: boolean
}) => {
await Promise.all([
setIsSimpleInternetSearch(isSimpleInternetSearch),
setSearchProvider(searchProvider),
setTotalSearchResults(totalSearchResults),
- setIsVisitSpecificWebsite(visitSpecificWebsite)
+ setIsVisitSpecificWebsite(visitSpecificWebsite),
+ setSearxngJSONMode(searxngJSONMode),
+ setSearxngURL(searxngURL)
])
}
diff --git a/src/utils/search-provider.ts b/src/utils/search-provider.ts
index d623df2..404c13f 100644
--- a/src/utils/search-provider.ts
+++ b/src/utils/search-provider.ts
@@ -14,5 +14,9 @@ export const SUPPORTED_SERACH_PROVIDERS = [
{
label: "Brave",
value: "brave"
+ },
+ {
+ label: "Searxng",
+ value: "searxng"
}
]
\ No newline at end of file
diff --git a/src/web/search-engines/searxng.ts b/src/web/search-engines/searxng.ts
new file mode 100644
index 0000000..0dc2e64
--- /dev/null
+++ b/src/web/search-engines/searxng.ts
@@ -0,0 +1,158 @@
+import { urlRewriteRuntime } from "~/libs/runtime"
+import { cleanUrl } from "~/libs/clean-url"
+import { getSearxngURL, isSearxngJSONMode, getIsSimpleInternetSearch, totalSearchResults } from "@/services/search"
+import { pageAssistEmbeddingModel } from "@/models/embedding"
+import type { Document } from "@langchain/core/documents"
+import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
+import { MemoryVectorStore } from "langchain/vectorstores/memory"
+import { PageAssistHtmlLoader } from "~/loader/html"
+import {
+ defaultEmbeddingChunkOverlap,
+ defaultEmbeddingChunkSize,
+ defaultEmbeddingModelForRag,
+ getOllamaURL
+} from "~/services/ollama"
+
+interface SearxNGJSONResult {
+ title: string
+ url: string
+ content: string
+}
+
+interface SearxNGJSONResponse {
+ results: SearxNGJSONResult[]
+}
+
+export const searxngSearch = async (query: string) => {
+ const searxngURL = await getSearxngURL()
+ if (!searxngURL) {
+ throw new Error("SearXNG URL not configured")
+ }
+
+ const isJSONMode = await isSearxngJSONMode()
+ const results = isJSONMode
+ ? await searxngJSONSearch(searxngURL, query)
+ : await searxngWebSearch(searxngURL, query)
+
+ const TOTAL_SEARCH_RESULTS = await totalSearchResults()
+ const searchResults = results.slice(0, TOTAL_SEARCH_RESULTS)
+
+ const isSimpleMode = await getIsSimpleInternetSearch()
+
+ if (isSimpleMode) {
+ await getOllamaURL()
+ return searchResults.map((result) => {
+ return {
+ url: result.link,
+ content: result.content
+ }
+ })
+ }
+
+ const docs: Document>[] = []
+ try {
+ for (const result of searchResults) {
+ const loader = new PageAssistHtmlLoader({
+ html: "",
+ url: result.link
+ })
+
+ const documents = await loader.loadByURL()
+ documents.forEach((doc) => {
+ docs.push(doc)
+ })
+ }
+ } catch (error) {
+ console.error(error)
+ }
+
+ const ollamaUrl = await getOllamaURL()
+ const embeddingModel = await defaultEmbeddingModelForRag()
+ const ollamaEmbedding = await pageAssistEmbeddingModel({
+ model: embeddingModel || "",
+ baseUrl: cleanUrl(ollamaUrl)
+ })
+
+ const chunkSize = await defaultEmbeddingChunkSize()
+ const chunkOverlap = await defaultEmbeddingChunkOverlap()
+ const textSplitter = new RecursiveCharacterTextSplitter({
+ chunkSize,
+ chunkOverlap
+ })
+
+ const chunks = await textSplitter.splitDocuments(docs)
+ const store = new MemoryVectorStore(ollamaEmbedding)
+ await store.addDocuments(chunks)
+
+ const resultsWithEmbeddings = await store.similaritySearch(query, 3)
+
+ const searchResult = resultsWithEmbeddings.map((result) => {
+ return {
+ url: result.metadata.url,
+ content: result.pageContent
+ }
+ })
+
+ return searchResult
+}
+
+const searxngJSONSearch = async (baseURL: string, query: string) => {
+ const searchURL = `${cleanUrl(baseURL)}?q=${encodeURIComponent(query)}&format=json`
+
+ const abortController = new AbortController()
+ setTimeout(() => abortController.abort(), 20000)
+
+ try {
+ const response = await fetch(searchURL, {
+ signal: abortController.signal,
+ headers: {
+ 'Accept': 'application/json'
+ }
+ })
+
+ if (!response.ok) {
+ throw new Error(`SearXNG search failed: ${response.statusText}`)
+ }
+
+ const data = await response.json() as SearxNGJSONResponse
+
+ return data.results.map(result => ({
+ title: result.title,
+ link: result.url,
+ content: result.content
+ }))
+ } catch (error) {
+ console.error('SearXNG JSON search failed:', error)
+ return []
+ }
+}
+
+const searxngWebSearch = async (baseURL: string, query: string) => {
+ const searchURL = `${cleanUrl(baseURL)}?q=${encodeURIComponent(query)}`
+
+ await urlRewriteRuntime(cleanUrl(searchURL), "searxng")
+
+ const abortController = new AbortController()
+ setTimeout(() => abortController.abort(), 10000)
+
+ try {
+ const htmlString = await fetch(searchURL, {
+ signal: abortController.signal
+ }).then(response => response.text())
+
+ const parser = new DOMParser()
+ const doc = parser.parseFromString(htmlString, "text/html")
+
+ const searchResults = Array.from(doc.querySelectorAll("article.result")).map(result => {
+ const title = result.querySelector("h3")?.textContent?.trim()
+ const link = result.querySelector("a.url_header")?.getAttribute("href")
+ const content = result.querySelector("p.content")?.textContent?.trim()
+ return { title, link, content }
+ }).filter(result => result.title && result.link && result.content)
+
+ return searchResults
+ } catch (error) {
+ console.error('SearXNG web search failed:', error)
+ return []
+ }
+}
diff --git a/src/web/web.ts b/src/web/web.ts
index 88aabc4..6c48f1b 100644
--- a/src/web/web.ts
+++ b/src/web/web.ts
@@ -5,6 +5,7 @@ import { getIsVisitSpecificWebsite, getSearchProvider } from "@/services/search"
import { webSogouSearch } from "./search-engines/sogou"
import { webBraveSearch } from "./search-engines/brave"
import { getWebsiteFromQuery, processSingleWebsite } from "./website"
+import { searxngSearch } from "./search-engines/searxng"
const getHostName = (url: string) => {
try {
@@ -23,6 +24,8 @@ const searchWeb = (provider: string, query: string) => {
return webSogouSearch(query)
case "brave":
return webBraveSearch(query)
+ case "searxng":
+ return searxngSearch(query)
default:
return webGoogleSearch(query)
}
@@ -51,7 +54,6 @@ export const getSystemPromptForWeb = async (query: string) => {
}
-
const search_results = search
.map(
(result, idx) =>
diff --git a/wxt.config.ts b/wxt.config.ts
index 18b2a44..abf8cda 100644
--- a/wxt.config.ts
+++ b/wxt.config.ts
@@ -50,7 +50,7 @@ export default defineConfig({
outDir: "build",
manifest: {
- version: "1.3.5",
+ version: "1.3.6",
name:
process.env.TARGET === "firefox"
? "Page Assist - A Web UI for Local AI Models"