Update component imports and add conditional focus in PlaygroundForm
This commit is contained in:
parent
0351beeaae
commit
a87c56061c
@ -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 (
|
||||
<div>
|
||||
@ -87,6 +116,41 @@ export default function OptionLayout({
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-lg font-thin text-zinc-300 dark:text-zinc-600">
|
||||
{"/"}
|
||||
</span>
|
||||
<div>
|
||||
<Select
|
||||
size="large"
|
||||
loading={isPromptLoading}
|
||||
showSearch
|
||||
placeholder="Select a prompt"
|
||||
className="w-60"
|
||||
allowClear
|
||||
onChange={handlePromptChange}
|
||||
value={selectedSystemPrompt}
|
||||
filterOption={(input, option) =>
|
||||
option.label.key
|
||||
.toLowerCase()
|
||||
.indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
options={prompts?.map((prompt) => ({
|
||||
label: (
|
||||
<span
|
||||
key={prompt.title}
|
||||
className="flex flex-row justify-between items-center">
|
||||
{prompt.title}
|
||||
{prompt.is_system ? (
|
||||
<ComputerIcon className="w-4 h-4" />
|
||||
) : (
|
||||
<ZapIcon className="w-4 h-4" />
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
value: prompt.id
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-1 justify-end px-4">
|
||||
<div className="ml-4 flex items-center md:ml-6">
|
@ -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({
|
||||
|
@ -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) => (
|
||||
<Tag color={is_system ? "green" : "blue"}>
|
||||
{is_system ? "Yes" : "No"}
|
||||
</Tag>
|
||||
)
|
||||
render: (is_system) =>
|
||||
is_system ? (
|
||||
<span className="flex justify-between">
|
||||
<Computer className="w-5 h-5 mr-3" />
|
||||
System Prompt
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex justify-between">
|
||||
<Zap className="w-5 h-5 mr-3" />
|
||||
Quick Prompt
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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 = () => {
|
||||
|
@ -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 = () => {
|
||||
|
@ -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 = () => {
|
||||
|
@ -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 = () => {
|
||||
|
@ -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 = () => {
|
||||
|
@ -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<State>((set) => ({
|
||||
@ -81,4 +87,8 @@ export const useStoreMessageOption = create<State>((set) => ({
|
||||
setWebSearch: (webSearch) => set({ webSearch }),
|
||||
isSearchingInternet: false,
|
||||
setIsSearchingInternet: (isSearchingInternet) => set({ isSearchingInternet }),
|
||||
selectedSystemPrompt: null,
|
||||
setSelectedSystemPrompt: (selectedSystemPrompt) => set({ selectedSystemPrompt }),
|
||||
selectedQuickPrompt: null,
|
||||
setSelectedQuickPrompt: (selectedQuickPrompt) => set({ selectedQuickPrompt }),
|
||||
}))
|
||||
|
24
src/utils/select-varaible.ts
Normal file
24
src/utils/select-varaible.ts
Normal file
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user