Add deleteChatHistory method to PageAssitDatabase class and systemPromptForNonRagOption functions to ollama service
This commit is contained in:
@@ -15,11 +15,13 @@ import logoImage from "data-base64:~assets/icon.png"
|
||||
|
||||
import { Link, useParams, useLocation, useNavigate } from "react-router-dom"
|
||||
import { Sidebar } from "./Sidebar"
|
||||
import { Drawer, Layout, Select } from "antd"
|
||||
import { Drawer, Layout, Modal, Select } from "antd"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { fetchModels } from "~services/ollama"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { PanelLeftIcon, Settings2 } from "lucide-react"
|
||||
import { Settings } from "./Settings"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
|
||||
const navigation = [
|
||||
{ name: "Embed", href: "/bot/:id", icon: TagIcon },
|
||||
@@ -51,8 +53,7 @@ export default function OptionLayout({
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false)
|
||||
const params = useParams<{ id: string }>()
|
||||
const location = useLocation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const {
|
||||
data: models,
|
||||
@@ -66,9 +67,10 @@ export default function OptionLayout({
|
||||
|
||||
const { selectedModel, setSelectedModel } = useMessageOption()
|
||||
|
||||
|
||||
return (
|
||||
<Layout className="bg-white dark:bg-[#171717] md:flex">
|
||||
<div className="flex items-center p-3 fixed flex-row justify-between border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-[#171717] w-full z-10">
|
||||
<div className="flex items-center p-3 fixed flex-row justify-between border-b border-gray-200 dark:border-gray-600 bg-white dark:bg-[#171717] w-full z-10">
|
||||
<div className="flex items-center flex-row gap-3">
|
||||
<div>
|
||||
<button
|
||||
@@ -92,7 +94,12 @@ export default function OptionLayout({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button className="text-gray-500 dark:text-gray-400">
|
||||
<button>
|
||||
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setOpen(true)}
|
||||
className="text-gray-500 dark:text-gray-400">
|
||||
<CogIcon className="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -104,10 +111,19 @@ export default function OptionLayout({
|
||||
placement="left"
|
||||
closeIcon={null}
|
||||
onClose={() => setSidebarOpen(false)}
|
||||
open={sidebarOpen}
|
||||
>
|
||||
open={sidebarOpen}>
|
||||
<Sidebar />
|
||||
</Drawer>
|
||||
|
||||
<Modal
|
||||
open={open}
|
||||
width={800}
|
||||
title={"Settings"}
|
||||
onOk={() => setOpen(false)}
|
||||
footer={null}
|
||||
onCancel={() => setOpen(false)}>
|
||||
<Settings setClose={() => setOpen(false)} />
|
||||
</Modal>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { PlaygroundMessage } from "./PlaygroundMessage"
|
||||
import { PlaygroundEmpty } from "./PlaygroundEmpty"
|
||||
|
||||
export const PlaygroundChat = () => {
|
||||
const { messages } = useMessageOption()
|
||||
@@ -13,7 +14,11 @@ export const PlaygroundChat = () => {
|
||||
})
|
||||
return (
|
||||
<div className="grow flex flex-col md:translate-x-0 transition-transform duration-300 ease-in-out">
|
||||
{/* {messages.length === 0 && <div>no message</div>} */}
|
||||
{messages.length === 0 && (
|
||||
<div className="mt-32">
|
||||
<PlaygroundEmpty />
|
||||
</div>
|
||||
)}
|
||||
{messages.length > 0 && <div className="w-full h-14 flex-shrink-0"></div>}
|
||||
{messages.map((message, index) => (
|
||||
<PlaygroundMessage
|
||||
|
||||
86
src/components/Option/Playground/PlaygroundEmpty.tsx
Normal file
86
src/components/Option/Playground/PlaygroundEmpty.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import {
|
||||
getOllamaURL,
|
||||
isOllamaRunning,
|
||||
setOllamaURL as saveOllamaURL
|
||||
} from "~services/ollama"
|
||||
|
||||
export const PlaygroundEmpty = () => {
|
||||
const [ollamaURL, setOllamaURL] = useState<string>("")
|
||||
const {
|
||||
data: ollamaInfo,
|
||||
status: ollamaStatus,
|
||||
refetch,
|
||||
isRefetching
|
||||
} = useQuery({
|
||||
queryKey: ["ollamaStatus"],
|
||||
queryFn: async () => {
|
||||
const ollamaURL = await getOllamaURL()
|
||||
const isOk = await isOllamaRunning()
|
||||
|
||||
return {
|
||||
isOk,
|
||||
ollamaURL
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (ollamaInfo?.ollamaURL) {
|
||||
setOllamaURL(ollamaInfo.ollamaURL)
|
||||
}
|
||||
}, [ollamaInfo])
|
||||
|
||||
return (
|
||||
<div className="mx-auto sm:max-w-xl px-4 mt-10">
|
||||
<div className="rounded-lg justify-center items-center flex flex-col border p-8 bg-white dark:bg-[#262626] shadow-sm dark:border-gray-600">
|
||||
{(ollamaStatus === "pending" || isRefetching) && (
|
||||
<div className="inline-flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-blue-500 rounded-full animate-bounce"></div>
|
||||
<p className="dark:text-gray-400 text-gray-900">
|
||||
Searching for Your Ollama 🦙
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{!isRefetching && ollamaStatus === "success" ? (
|
||||
ollamaInfo.isOk ? (
|
||||
<div className="inline-flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-green-500 rounded-full"></div>
|
||||
<p className="dark:text-gray-400 text-gray-900">
|
||||
Ollama is running 🦙
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col space-y-2 justify-center items-center">
|
||||
<div className="inline-flex space-x-2">
|
||||
<div className="w-3 h-3 bg-red-500 rounded-full"></div>
|
||||
<p className="dark:text-gray-400 text-gray-900">
|
||||
Unable to connect to Ollama 🦙
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input
|
||||
className="bg-gray-100 dark:bg-[#262626] dark:text-gray-100 rounded-md px-4 py-2 mt-2 w-full"
|
||||
type="url"
|
||||
value={ollamaURL}
|
||||
onChange={(e) => setOllamaURL(e.target.value)}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
saveOllamaURL(ollamaURL)
|
||||
refetch()
|
||||
}}
|
||||
className="bg-pink-500 mt-4 hover:bg-pink-600 text-white px-4 py-2 rounded-md dark:bg-pink-600 dark:hover:bg-pink-700">
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="p-3 md:p-6 md:bg-white dark:bg-black border rounded-t-xl border-black/10 dark:border-gray-800">
|
||||
<div className="p-3 md:p-6 md:bg-white dark:bg-[#262626] border rounded-t-xl border-black/10 dark:border-gray-600">
|
||||
<div className="flex-grow space-y-6 ">
|
||||
<div
|
||||
className={`h-full rounded-md shadow relative ${
|
||||
@@ -82,7 +82,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
onClick={() => {
|
||||
form.setFieldValue("image", "")
|
||||
}}
|
||||
className="absolute top-2 right-2 bg-white dark:bg-black p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100">
|
||||
className="absolute top-2 right-2 bg-white dark:bg-[#262626] p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100">
|
||||
<XMarkIcon className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -109,7 +109,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
})
|
||||
})}
|
||||
className="shrink-0 flex-grow flex items-center ">
|
||||
<div className="flex items-center p-2 rounded-2xl border bg-gray-100 w-full dark:bg-black dark:border-gray-800">
|
||||
<div className="flex items-center p-2 rounded-2xl border bg-gray-100 w-full dark:bg-[#262626] dark:border-gray-600">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -162,7 +162,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
/>
|
||||
<button
|
||||
disabled={isSending || form.values.message.length === 0}
|
||||
className="ml-2 flex items-center justify-center w-10 h-10 text-white bg-black rounded-xl disabled:opacity-50">
|
||||
className="ml-2 flex items-center justify-center w-10 h-10 text-white bg-[#262626] rounded-xl disabled:opacity-50">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
|
||||
39
src/components/Option/Settings.tsx
Normal file
39
src/components/Option/Settings.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tabs } from "antd"
|
||||
import { SettingsOllama } from "./Settings/ollama"
|
||||
import { SettingPrompt } from "./Settings/prompt"
|
||||
import { SettingOther } from "./Settings/other"
|
||||
|
||||
type Props = {
|
||||
setClose: (close: boolean) => void
|
||||
}
|
||||
|
||||
export const Settings = ({ setClose }: Props) => {
|
||||
return (
|
||||
<div className="my-6">
|
||||
<Tabs
|
||||
tabPosition="left"
|
||||
defaultActiveKey="1"
|
||||
items={[
|
||||
{
|
||||
id: "1",
|
||||
key: "1",
|
||||
label: "Prompt",
|
||||
children: <SettingPrompt />
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
key: "2",
|
||||
label: "Ollama",
|
||||
children: <SettingsOllama />
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
key: "3",
|
||||
label: "Other",
|
||||
children: <SettingOther />
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
55
src/components/Option/Settings/ollama.tsx
Normal file
55
src/components/Option/Settings/ollama.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { useEffect, useState } from "react"
|
||||
import { SaveButton } from "~components/Common/SaveButton"
|
||||
import { getOllamaURL, setOllamaURL as saveOllamaURL } from "~services/ollama"
|
||||
|
||||
export const SettingsOllama = () => {
|
||||
const [ollamaURL, setOllamaURL] = useState<string>("")
|
||||
const { data: ollamaInfo } = useQuery({
|
||||
queryKey: ["fetchOllamURL"],
|
||||
queryFn: async () => {
|
||||
const ollamaURL = await getOllamaURL()
|
||||
|
||||
return {
|
||||
ollamaURL
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (ollamaInfo?.ollamaURL) {
|
||||
setOllamaURL(ollamaInfo.ollamaURL)
|
||||
}
|
||||
}, [ollamaInfo])
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="ollamaURL"
|
||||
className="text-sm font-medium dark:text-gray-200">
|
||||
Ollama URL
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
id="ollamaURL"
|
||||
value={ollamaURL}
|
||||
onChange={(e) => {
|
||||
setOllamaURL(e.target.value)
|
||||
}}
|
||||
placeholder="Your Ollama URL"
|
||||
className="w-full p-2 border border-gray-300 rounded-md dark:bg-[#262626] dark:text-gray-100"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<SaveButton
|
||||
onClick={() => {
|
||||
saveOllamaURL(ollamaURL)
|
||||
}}
|
||||
className="mt-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
52
src/components/Option/Settings/other.tsx
Normal file
52
src/components/Option/Settings/other.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useQueryClient } from "@tanstack/react-query"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { PageAssitDatabase } from "~libs/db"
|
||||
|
||||
export const SettingOther = () => {
|
||||
const { clearChat } = useMessageOption()
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const { mode, toggleDarkMode } = useDarkMode()
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex flex-row justify-between">
|
||||
<span className="text-gray-500 dark:text-gray-400 text-lg">
|
||||
Change Theme
|
||||
</span>
|
||||
|
||||
<button
|
||||
onClick={toggleDarkMode}
|
||||
className="bg-blue-500 dark:bg-blue-600 text-white dark:text-gray-200 px-4 py-2 rounded-md">
|
||||
{mode === "dark" ? "Light" : "Dark"}
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between">
|
||||
<span className="text-gray-500 dark:text-gray-400 text-lg">
|
||||
Delete Chat History
|
||||
</span>
|
||||
|
||||
<button
|
||||
onClick={async () => {
|
||||
const confirm = window.confirm(
|
||||
"Are you sure you want to delete your chat history? This action cannot be undone."
|
||||
)
|
||||
|
||||
if (confirm) {
|
||||
const db = new PageAssitDatabase()
|
||||
await db.deleteChatHistory()
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["fetchChatHistory"]
|
||||
})
|
||||
clearChat()
|
||||
}
|
||||
}}
|
||||
className="bg-red-500 dark:bg-red-600 text-white dark:text-gray-200 px-4 py-2 rounded-md">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
56
src/components/Option/Settings/prompt.tsx
Normal file
56
src/components/Option/Settings/prompt.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { useEffect, useState } from "react"
|
||||
import { SaveButton } from "~components/Common/SaveButton"
|
||||
import {
|
||||
setSystemPromptForNonRagOption,
|
||||
systemPromptForNonRagOption
|
||||
} from "~services/ollama"
|
||||
|
||||
export const SettingPrompt = () => {
|
||||
const [ollamaPrompt, setOllamaPrompt] = useState<string>("")
|
||||
const { data: ollamaInfo } = useQuery({
|
||||
queryKey: ["fetchOllaPrompt"],
|
||||
queryFn: async () => {
|
||||
const prompt = await systemPromptForNonRagOption()
|
||||
|
||||
return {
|
||||
prompt
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (ollamaInfo?.prompt) {
|
||||
setOllamaPrompt(ollamaInfo.prompt)
|
||||
}
|
||||
}, [ollamaInfo])
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div>
|
||||
<label htmlFor="ollamaPrompt" className="text-sm font-medium dark:text-gray-200">
|
||||
System Prompt
|
||||
</label>
|
||||
<textarea
|
||||
value={ollamaPrompt}
|
||||
rows={5}
|
||||
id="ollamaPrompt"
|
||||
placeholder="Your System Prompt"
|
||||
onChange={(e) => {
|
||||
setOllamaPrompt(e.target.value)
|
||||
}}
|
||||
className="w-full p-2 border border-gray-300 rounded-md dark:bg-[#262626] dark:text-gray-100"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<SaveButton
|
||||
onClick={() => {
|
||||
setSystemPromptForNonRagOption(ollamaPrompt)
|
||||
}}
|
||||
className="mt-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user