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 React, { useState } from "react" | ||||||
| 
 | 
 | ||||||
| import { useLocation, NavLink } from "react-router-dom" | import { useLocation, NavLink } from "react-router-dom" | ||||||
| import { Sidebar } from "./Sidebar" | import { Sidebar } from "../Option/Sidebar" | ||||||
| import { Drawer, Select, Tooltip } from "antd" | import { Drawer, Select, Tooltip } from "antd" | ||||||
| import { useQuery } from "@tanstack/react-query" | import { useQuery } from "@tanstack/react-query" | ||||||
| import { getAllModels } from "~services/ollama" | import { getAllModels } from "~services/ollama" | ||||||
| @ -9,10 +9,13 @@ import { useMessageOption } from "~hooks/useMessageOption" | |||||||
| import { | import { | ||||||
|   ChevronLeft, |   ChevronLeft, | ||||||
|   CogIcon, |   CogIcon, | ||||||
|  |   ComputerIcon, | ||||||
|   GithubIcon, |   GithubIcon, | ||||||
|   PanelLeftIcon, |   PanelLeftIcon, | ||||||
|   SquarePen |   SquarePen, | ||||||
|  |   ZapIcon | ||||||
| } from "lucide-react" | } from "lucide-react" | ||||||
|  | import { getAllPrompts } from "~libs/db" | ||||||
| 
 | 
 | ||||||
| export default function OptionLayout({ | export default function OptionLayout({ | ||||||
|   children |   children | ||||||
| @ -20,6 +23,14 @@ export default function OptionLayout({ | |||||||
|   children: React.ReactNode |   children: React.ReactNode | ||||||
| }) { | }) { | ||||||
|   const [sidebarOpen, setSidebarOpen] = useState(false) |   const [sidebarOpen, setSidebarOpen] = useState(false) | ||||||
|  |   const { | ||||||
|  |     selectedModel, | ||||||
|  |     setSelectedModel, | ||||||
|  |     clearChat, | ||||||
|  |     selectedSystemPrompt, | ||||||
|  |     setSelectedQuickPrompt, | ||||||
|  |     setSelectedSystemPrompt | ||||||
|  |   } = useMessageOption() | ||||||
| 
 | 
 | ||||||
|   const { |   const { | ||||||
|     data: models, |     data: models, | ||||||
| @ -27,12 +38,30 @@ export default function OptionLayout({ | |||||||
|     isFetching: isModelsFetching |     isFetching: isModelsFetching | ||||||
|   } = useQuery({ |   } = useQuery({ | ||||||
|     queryKey: ["fetchModel"], |     queryKey: ["fetchModel"], | ||||||
|     queryFn: getAllModels, |     queryFn: () => getAllModels({ returnEmpty: true }), | ||||||
|     refetchInterval: 15000 |     refetchInterval: 15000 | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  |   const { data: prompts, isLoading: isPromptLoading } = useQuery({ | ||||||
|  |     queryKey: ["fetchAllPromptsLayout"], | ||||||
|  |     queryFn: getAllPrompts | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|   const { pathname } = useLocation() |   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 ( |   return ( | ||||||
|     <div> |     <div> | ||||||
| @ -87,6 +116,41 @@ export default function OptionLayout({ | |||||||
|                   }))} |                   }))} | ||||||
|                 /> |                 /> | ||||||
|               </div> |               </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> | ||||||
|             <div className="flex flex-1 justify-end px-4"> |             <div className="flex flex-1 justify-end px-4"> | ||||||
|               <div className="ml-4 flex items-center md:ml-6"> |               <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 { 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 { getVariable } from "~utils/select-varaible" | ||||||
| 
 | 
 | ||||||
| type Props = { | type Props = { | ||||||
|   dropedFile: File | undefined |   dropedFile: File | undefined | ||||||
| @ -21,7 +22,11 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { | |||||||
| 
 | 
 | ||||||
|   const textAreaFocus = () => { |   const textAreaFocus = () => { | ||||||
|     if (textareaRef.current) { |     if (textareaRef.current) { | ||||||
|       textareaRef.current.focus() |       if ( | ||||||
|  |         textareaRef.current.selectionStart === textareaRef.current.selectionEnd | ||||||
|  |       ) { | ||||||
|  |         textareaRef.current.focus() | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   const form = useForm({ |   const form = useForm({ | ||||||
| @ -65,7 +70,9 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { | |||||||
|     stopStreamingRequest, |     stopStreamingRequest, | ||||||
|     streaming: isSending, |     streaming: isSending, | ||||||
|     webSearch, |     webSearch, | ||||||
|     setWebSearch |     setWebSearch, | ||||||
|  |     selectedQuickPrompt, | ||||||
|  |     setSelectedQuickPrompt | ||||||
|   } = useMessageOption() |   } = useMessageOption() | ||||||
| 
 | 
 | ||||||
|   const { isListening, start, stop, transcript } = useSpeechRecognition() |   const { isListening, start, stop, transcript } = useSpeechRecognition() | ||||||
| @ -77,6 +84,22 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { | |||||||
|     } |     } | ||||||
|   }, [transcript]) |   }, [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 queryClient = useQueryClient() | ||||||
| 
 | 
 | ||||||
|   const { mutateAsync: sendMessage } = useMutation({ |   const { mutateAsync: sendMessage } = useMutation({ | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" | |||||||
| import { | import { | ||||||
|   Skeleton, |   Skeleton, | ||||||
|   Table, |   Table, | ||||||
|   Tag, |  | ||||||
|   Tooltip, |   Tooltip, | ||||||
|   notification, |   notification, | ||||||
|   Modal, |   Modal, | ||||||
| @ -10,7 +9,7 @@ import { | |||||||
|   Form, |   Form, | ||||||
|   Switch |   Switch | ||||||
| } from "antd" | } from "antd" | ||||||
| import { Trash2, Pen } from "lucide-react" | import { Trash2, Pen, Computer, Zap } from "lucide-react" | ||||||
| import { useState } from "react" | import { useState } from "react" | ||||||
| import { | import { | ||||||
|   deletePromptById, |   deletePromptById, | ||||||
| @ -131,14 +130,21 @@ export const PromptBody = () => { | |||||||
|                 key: "content" |                 key: "content" | ||||||
|               }, |               }, | ||||||
|               { |               { | ||||||
|                 title: "Is System Prompt", |                 title: "Prompt Type", | ||||||
|                 dataIndex: "is_system", |                 dataIndex: "is_system", | ||||||
|                 key: "is_system", |                 key: "is_system", | ||||||
|                 render: (is_system) => ( |                 render: (is_system) => | ||||||
|                   <Tag color={is_system ? "green" : "blue"}> |                   is_system ? ( | ||||||
|                     {is_system ? "Yes" : "No"} |                     <span className="flex justify-between"> | ||||||
|                   </Tag> |                        <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", |                 title: "Action", | ||||||
|  | |||||||
| @ -14,7 +14,12 @@ import { | |||||||
|   SystemMessage |   SystemMessage | ||||||
| } from "@langchain/core/messages" | } from "@langchain/core/messages" | ||||||
| import { useStoreMessageOption } from "~store/option" | 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 { useNavigate } from "react-router-dom" | ||||||
| import { notification } from "antd" | import { notification } from "antd" | ||||||
| import { getSystemPromptForWeb } from "~web/web" | import { getSystemPromptForWeb } from "~web/web" | ||||||
| @ -102,7 +107,11 @@ export const useMessageOption = () => { | |||||||
|     webSearch, |     webSearch, | ||||||
|     setWebSearch, |     setWebSearch, | ||||||
|     isSearchingInternet, |     isSearchingInternet, | ||||||
|     setIsSearchingInternet |     setIsSearchingInternet, | ||||||
|  |     selectedQuickPrompt, | ||||||
|  |     setSelectedQuickPrompt, | ||||||
|  |     selectedSystemPrompt, | ||||||
|  |     setSelectedSystemPrompt | ||||||
|   } = useStoreMessageOption() |   } = useStoreMessageOption() | ||||||
| 
 | 
 | ||||||
|   const navigate = useNavigate() |   const navigate = useNavigate() | ||||||
| @ -310,7 +319,7 @@ export const useMessageOption = () => { | |||||||
|       setIsProcessing(false) |       setIsProcessing(false) | ||||||
|       setStreaming(false) |       setStreaming(false) | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       (e) |       e | ||||||
| 
 | 
 | ||||||
|       if (e?.name === "AbortError") { |       if (e?.name === "AbortError") { | ||||||
|         newMessage[appendingIndex].message = newMessage[ |         newMessage[appendingIndex].message = newMessage[ | ||||||
| @ -406,6 +415,7 @@ export const useMessageOption = () => { | |||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       const prompt = await systemPromptForNonRagOption() |       const prompt = await systemPromptForNonRagOption() | ||||||
|  |       const selectedPrompt = await getPromptById(selectedSystemPrompt) | ||||||
| 
 | 
 | ||||||
|       message = message.trim().replaceAll("\n", " ") |       message = message.trim().replaceAll("\n", " ") | ||||||
| 
 | 
 | ||||||
| @ -434,7 +444,7 @@ export const useMessageOption = () => { | |||||||
| 
 | 
 | ||||||
|       const applicationChatHistory = generateHistory(history) |       const applicationChatHistory = generateHistory(history) | ||||||
| 
 | 
 | ||||||
|       if (prompt) { |       if (prompt && !selectedPrompt) { | ||||||
|         applicationChatHistory.unshift( |         applicationChatHistory.unshift( | ||||||
|           new SystemMessage({ |           new SystemMessage({ | ||||||
|             content: [ |             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( |       const chunks = await ollama.stream( | ||||||
|         [...applicationChatHistory, humanMessage], |         [...applicationChatHistory, humanMessage], | ||||||
|         { |         { | ||||||
| @ -526,7 +549,6 @@ export const useMessageOption = () => { | |||||||
|       setIsProcessing(false) |       setIsProcessing(false) | ||||||
|       setStreaming(false) |       setStreaming(false) | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
| 
 |  | ||||||
|       if (e?.name === "AbortError") { |       if (e?.name === "AbortError") { | ||||||
|         newMessage[appendingIndex].message = newMessage[ |         newMessage[appendingIndex].message = newMessage[ | ||||||
|           appendingIndex |           appendingIndex | ||||||
| @ -644,6 +666,11 @@ export const useMessageOption = () => { | |||||||
|     regenerateLastMessage, |     regenerateLastMessage, | ||||||
|     webSearch, |     webSearch, | ||||||
|     setWebSearch, |     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) => { | export const getPromptById = async (id: string) => { | ||||||
|  |   if (!id || id.trim() === "") return null | ||||||
|   const db = new PageAssitDatabase() |   const db = new PageAssitDatabase() | ||||||
|   return await db.getPromptById(id) |   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" | import { Playground } from "~components/Option/Playground/Playground" | ||||||
| 
 | 
 | ||||||
| export const OptionIndex = () => { | export const OptionIndex = () => { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout" | import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout" | ||||||
| import OptionLayout from "~components/Option/Layout" | import OptionLayout from "~components/Layouts/Layout" | ||||||
| import { ModelsBody } from "~components/Option/Models" | import { ModelsBody } from "~components/Option/Models" | ||||||
| 
 | 
 | ||||||
| export const OptionModal = () => { | export const OptionModal = () => { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout" | import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout" | ||||||
| import OptionLayout from "~components/Option/Layout" | import OptionLayout from "~components/Layouts/Layout" | ||||||
| import { PromptBody } from "~components/Option/Prompt" | import { PromptBody } from "~components/Option/Prompt" | ||||||
| 
 | 
 | ||||||
| export const OptionPrompt = () => { | export const OptionPrompt = () => { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout" | 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" | import { SettingOther } from "~components/Option/Settings/other" | ||||||
| 
 | 
 | ||||||
| export const OptionSettings = () => { | export const OptionSettings = () => { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout" | 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" | import { SettingsOllama } from "~components/Option/Settings/ollama" | ||||||
| 
 | 
 | ||||||
| export const OptionOllamaSettings = () => { | export const OptionOllamaSettings = () => { | ||||||
|  | |||||||
| @ -51,6 +51,12 @@ type State = { | |||||||
|   setWebSearch: (webSearch: boolean) => void; |   setWebSearch: (webSearch: boolean) => void; | ||||||
|   isSearchingInternet: boolean; |   isSearchingInternet: boolean; | ||||||
|   setIsSearchingInternet: (isSearchingInternet: boolean) => void; |   setIsSearchingInternet: (isSearchingInternet: boolean) => void; | ||||||
|  | 
 | ||||||
|  |   selectedSystemPrompt: string | null | ||||||
|  |   setSelectedSystemPrompt: (selectedSystemPrompt: string) => void | ||||||
|  | 
 | ||||||
|  |   selectedQuickPrompt: string | null | ||||||
|  |   setSelectedQuickPrompt: (selectedQuickPrompt: string) => void | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const useStoreMessageOption = create<State>((set) => ({ | export const useStoreMessageOption = create<State>((set) => ({ | ||||||
| @ -81,4 +87,8 @@ export const useStoreMessageOption = create<State>((set) => ({ | |||||||
|   setWebSearch: (webSearch) => set({ webSearch }), |   setWebSearch: (webSearch) => set({ webSearch }), | ||||||
|   isSearchingInternet: false, |   isSearchingInternet: false, | ||||||
|   setIsSearchingInternet: (isSearchingInternet) => set({ isSearchingInternet }), |   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