diff --git a/src/components/Option/Layout.tsx b/src/components/Layouts/Layout.tsx
similarity index 69%
rename from src/components/Option/Layout.tsx
rename to src/components/Layouts/Layout.tsx
index e998864..4c08354 100644
--- a/src/components/Option/Layout.tsx
+++ b/src/components/Layouts/Layout.tsx
@@ -1,7 +1,7 @@
import React, { useState } from "react"
import { useLocation, NavLink } from "react-router-dom"
-import { Sidebar } from "./Sidebar"
+import { Sidebar } from "../Option/Sidebar"
import { Drawer, Select, Tooltip } from "antd"
import { useQuery } from "@tanstack/react-query"
import { getAllModels } from "~services/ollama"
@@ -9,10 +9,13 @@ import { useMessageOption } from "~hooks/useMessageOption"
import {
ChevronLeft,
CogIcon,
+ ComputerIcon,
GithubIcon,
PanelLeftIcon,
- SquarePen
+ SquarePen,
+ ZapIcon
} from "lucide-react"
+import { getAllPrompts } from "~libs/db"
export default function OptionLayout({
children
@@ -20,6 +23,14 @@ export default function OptionLayout({
children: React.ReactNode
}) {
const [sidebarOpen, setSidebarOpen] = useState(false)
+ const {
+ selectedModel,
+ setSelectedModel,
+ clearChat,
+ selectedSystemPrompt,
+ setSelectedQuickPrompt,
+ setSelectedSystemPrompt
+ } = useMessageOption()
const {
data: models,
@@ -27,12 +38,30 @@ export default function OptionLayout({
isFetching: isModelsFetching
} = useQuery({
queryKey: ["fetchModel"],
- queryFn: getAllModels,
+ queryFn: () => getAllModels({ returnEmpty: true }),
refetchInterval: 15000
})
+ const { data: prompts, isLoading: isPromptLoading } = useQuery({
+ queryKey: ["fetchAllPromptsLayout"],
+ queryFn: getAllPrompts
+ })
+
const { pathname } = useLocation()
- const { selectedModel, setSelectedModel, clearChat } = useMessageOption()
+
+ const getPromptInfoById = (id: string) => {
+ return prompts?.find((prompt) => prompt.id === id)
+ }
+
+ const handlePromptChange = (value: string) => {
+ const prompt = getPromptInfoById(value)
+ if (prompt?.is_system) {
+ setSelectedSystemPrompt(prompt.id)
+ } else {
+ setSelectedQuickPrompt(prompt.content)
+ setSelectedSystemPrompt(null)
+ }
+ }
return (
@@ -87,6 +116,41 @@ export default function OptionLayout({
}))}
/>
+
diff --git a/src/components/Option/Playground/PlaygroundForm.tsx b/src/components/Option/Playground/PlaygroundForm.tsx
index fc6aa4a..1be9399 100644
--- a/src/components/Option/Playground/PlaygroundForm.tsx
+++ b/src/components/Option/Playground/PlaygroundForm.tsx
@@ -10,6 +10,7 @@ import { useSpeechRecognition } from "~hooks/useSpeechRecognition"
import { useWebUI } from "~store/webui"
import { defaultEmbeddingModelForRag } from "~services/ollama"
import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react"
+import { getVariable } from "~utils/select-varaible"
type Props = {
dropedFile: File | undefined
@@ -21,7 +22,11 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
const textAreaFocus = () => {
if (textareaRef.current) {
- textareaRef.current.focus()
+ if (
+ textareaRef.current.selectionStart === textareaRef.current.selectionEnd
+ ) {
+ textareaRef.current.focus()
+ }
}
}
const form = useForm({
@@ -65,7 +70,9 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
stopStreamingRequest,
streaming: isSending,
webSearch,
- setWebSearch
+ setWebSearch,
+ selectedQuickPrompt,
+ setSelectedQuickPrompt
} = useMessageOption()
const { isListening, start, stop, transcript } = useSpeechRecognition()
@@ -77,6 +84,22 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
}
}, [transcript])
+ React.useEffect(() => {
+ if (selectedQuickPrompt) {
+ const word = getVariable(selectedQuickPrompt)
+ form.setFieldValue("message", selectedQuickPrompt)
+ if (word) {
+ textareaRef.current?.focus()
+ const interval = setTimeout(() => {
+ textareaRef.current?.setSelectionRange(word.start, word.end)
+ }, 100)
+ return () => {
+ clearInterval(interval)
+ }
+ }
+ }
+ }, [selectedQuickPrompt])
+
const queryClient = useQueryClient()
const { mutateAsync: sendMessage } = useMutation({
diff --git a/src/components/Option/Prompt/index.tsx b/src/components/Option/Prompt/index.tsx
index 3672a6b..14aaf77 100644
--- a/src/components/Option/Prompt/index.tsx
+++ b/src/components/Option/Prompt/index.tsx
@@ -2,7 +2,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import {
Skeleton,
Table,
- Tag,
Tooltip,
notification,
Modal,
@@ -10,7 +9,7 @@ import {
Form,
Switch
} from "antd"
-import { Trash2, Pen } from "lucide-react"
+import { Trash2, Pen, Computer, Zap } from "lucide-react"
import { useState } from "react"
import {
deletePromptById,
@@ -131,14 +130,21 @@ export const PromptBody = () => {
key: "content"
},
{
- title: "Is System Prompt",
+ title: "Prompt Type",
dataIndex: "is_system",
key: "is_system",
- render: (is_system) => (
-
- {is_system ? "Yes" : "No"}
-
- )
+ render: (is_system) =>
+ is_system ? (
+
+
+ System Prompt
+
+ ) : (
+
+
+ Quick Prompt
+
+ )
},
{
title: "Action",
diff --git a/src/hooks/useMessageOption.tsx b/src/hooks/useMessageOption.tsx
index 8fc6846..07534d2 100644
--- a/src/hooks/useMessageOption.tsx
+++ b/src/hooks/useMessageOption.tsx
@@ -14,7 +14,12 @@ import {
SystemMessage
} from "@langchain/core/messages"
import { useStoreMessageOption } from "~store/option"
-import { removeMessageUsingHistoryId, saveHistory, saveMessage } from "~libs/db"
+import {
+ getPromptById,
+ removeMessageUsingHistoryId,
+ saveHistory,
+ saveMessage
+} from "~libs/db"
import { useNavigate } from "react-router-dom"
import { notification } from "antd"
import { getSystemPromptForWeb } from "~web/web"
@@ -102,7 +107,11 @@ export const useMessageOption = () => {
webSearch,
setWebSearch,
isSearchingInternet,
- setIsSearchingInternet
+ setIsSearchingInternet,
+ selectedQuickPrompt,
+ setSelectedQuickPrompt,
+ selectedSystemPrompt,
+ setSelectedSystemPrompt
} = useStoreMessageOption()
const navigate = useNavigate()
@@ -310,7 +319,7 @@ export const useMessageOption = () => {
setIsProcessing(false)
setStreaming(false)
} catch (e) {
- (e)
+ e
if (e?.name === "AbortError") {
newMessage[appendingIndex].message = newMessage[
@@ -406,6 +415,7 @@ export const useMessageOption = () => {
try {
const prompt = await systemPromptForNonRagOption()
+ const selectedPrompt = await getPromptById(selectedSystemPrompt)
message = message.trim().replaceAll("\n", " ")
@@ -434,7 +444,7 @@ export const useMessageOption = () => {
const applicationChatHistory = generateHistory(history)
- if (prompt) {
+ if (prompt && !selectedPrompt) {
applicationChatHistory.unshift(
new SystemMessage({
content: [
@@ -447,6 +457,19 @@ export const useMessageOption = () => {
)
}
+ if (selectedPrompt) {
+ applicationChatHistory.unshift(
+ new SystemMessage({
+ content: [
+ {
+ text: selectedPrompt.content,
+ type: "text"
+ }
+ ]
+ })
+ )
+ }
+
const chunks = await ollama.stream(
[...applicationChatHistory, humanMessage],
{
@@ -526,7 +549,6 @@ export const useMessageOption = () => {
setIsProcessing(false)
setStreaming(false)
} catch (e) {
-
if (e?.name === "AbortError") {
newMessage[appendingIndex].message = newMessage[
appendingIndex
@@ -644,6 +666,11 @@ export const useMessageOption = () => {
regenerateLastMessage,
webSearch,
setWebSearch,
- isSearchingInternet
+ isSearchingInternet,
+ setIsSearchingInternet,
+ selectedQuickPrompt,
+ setSelectedQuickPrompt,
+ selectedSystemPrompt,
+ setSelectedSystemPrompt
}
}
diff --git a/src/libs/db.ts b/src/libs/db.ts
index 75d53a6..6b78096 100644
--- a/src/libs/db.ts
+++ b/src/libs/db.ts
@@ -274,6 +274,7 @@ export const updatePrompt = async ({ content, id, title, is_system }: { id: stri
export const getPromptById = async (id: string) => {
+ if (!id || id.trim() === "") return null
const db = new PageAssitDatabase()
return await db.getPromptById(id)
}
\ No newline at end of file
diff --git a/src/routes/option-index.tsx b/src/routes/option-index.tsx
index 2c31db7..86a6a24 100644
--- a/src/routes/option-index.tsx
+++ b/src/routes/option-index.tsx
@@ -1,4 +1,4 @@
-import OptionLayout from "~components/Option/Layout"
+import OptionLayout from "~components/Layouts/Layout"
import { Playground } from "~components/Option/Playground/Playground"
export const OptionIndex = () => {
diff --git a/src/routes/option-settings-model.tsx b/src/routes/option-settings-model.tsx
index 7ea8b42..fb91b01 100644
--- a/src/routes/option-settings-model.tsx
+++ b/src/routes/option-settings-model.tsx
@@ -1,5 +1,5 @@
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
-import OptionLayout from "~components/Option/Layout"
+import OptionLayout from "~components/Layouts/Layout"
import { ModelsBody } from "~components/Option/Models"
export const OptionModal = () => {
diff --git a/src/routes/option-settings-prompt.tsx b/src/routes/option-settings-prompt.tsx
index abaa237..74d421f 100644
--- a/src/routes/option-settings-prompt.tsx
+++ b/src/routes/option-settings-prompt.tsx
@@ -1,5 +1,5 @@
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
-import OptionLayout from "~components/Option/Layout"
+import OptionLayout from "~components/Layouts/Layout"
import { PromptBody } from "~components/Option/Prompt"
export const OptionPrompt = () => {
diff --git a/src/routes/option-settings.tsx b/src/routes/option-settings.tsx
index ef4ff31..8c18b50 100644
--- a/src/routes/option-settings.tsx
+++ b/src/routes/option-settings.tsx
@@ -1,5 +1,5 @@
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
-import OptionLayout from "~components/Option/Layout"
+import OptionLayout from "~components/Layouts/Layout"
import { SettingOther } from "~components/Option/Settings/other"
export const OptionSettings = () => {
diff --git a/src/routes/options-settings-ollama.tsx b/src/routes/options-settings-ollama.tsx
index a8aebb1..d8e8c98 100644
--- a/src/routes/options-settings-ollama.tsx
+++ b/src/routes/options-settings-ollama.tsx
@@ -1,5 +1,5 @@
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
-import OptionLayout from "~components/Option/Layout"
+import OptionLayout from "~components/Layouts/Layout"
import { SettingsOllama } from "~components/Option/Settings/ollama"
export const OptionOllamaSettings = () => {
diff --git a/src/store/option.tsx b/src/store/option.tsx
index 802f40e..51e41c1 100644
--- a/src/store/option.tsx
+++ b/src/store/option.tsx
@@ -51,6 +51,12 @@ type State = {
setWebSearch: (webSearch: boolean) => void;
isSearchingInternet: boolean;
setIsSearchingInternet: (isSearchingInternet: boolean) => void;
+
+ selectedSystemPrompt: string | null
+ setSelectedSystemPrompt: (selectedSystemPrompt: string) => void
+
+ selectedQuickPrompt: string | null
+ setSelectedQuickPrompt: (selectedQuickPrompt: string) => void
}
export const useStoreMessageOption = create((set) => ({
@@ -81,4 +87,8 @@ export const useStoreMessageOption = create((set) => ({
setWebSearch: (webSearch) => set({ webSearch }),
isSearchingInternet: false,
setIsSearchingInternet: (isSearchingInternet) => set({ isSearchingInternet }),
+ selectedSystemPrompt: null,
+ setSelectedSystemPrompt: (selectedSystemPrompt) => set({ selectedSystemPrompt }),
+ selectedQuickPrompt: null,
+ setSelectedQuickPrompt: (selectedQuickPrompt) => set({ selectedQuickPrompt }),
}))
diff --git a/src/utils/select-varaible.ts b/src/utils/select-varaible.ts
new file mode 100644
index 0000000..5b354fb
--- /dev/null
+++ b/src/utils/select-varaible.ts
@@ -0,0 +1,24 @@
+export const getVariable = (text: string) => {
+ const regex = /{([^}]+)}/g;
+ let data : {
+ word: string,
+ start: number,
+ end: number
+ } | null = null;
+
+
+ let m: RegExpExecArray | null;
+
+ while ((m = regex.exec(text)) !== null) {
+ if (m.index === regex.lastIndex) {
+ regex.lastIndex++;
+ }
+ data = {
+ word: m[1],
+ start: m.index,
+ end: m.index + m[0].length
+ }
+ }
+
+ return data;
+}
\ No newline at end of file