Add localization for manage search feature

This commit is contained in:
n4ze3m 2024-03-31 00:36:12 +05:30
parent 12558c39d1
commit ea56a2ffa2
14 changed files with 503 additions and 281 deletions

View File

@ -203,5 +203,9 @@
"webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt" "webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt"
} }
} }
},
"manageSearch": {
"title": "Manage Web Search",
"heading": "Configure Web Search"
} }
} }

View File

@ -203,5 +203,9 @@
"webSearchFollowUpPromptPlaceholder": "Web検索フォローアッププロンプト" "webSearchFollowUpPromptPlaceholder": "Web検索フォローアッププロンプト"
} }
} }
},
"manageSearch": {
"title": "Web検索の管理",
"heading": "Web検索を設定する"
} }
} }

View File

@ -203,5 +203,9 @@
"webSearchFollowUpPromptPlaceholder": "നിങ്ങളുടെ വെബ് തിരയല്‍ തുടര്‍പ്രോംപ്റ്റ്" "webSearchFollowUpPromptPlaceholder": "നിങ്ങളുടെ വെബ് തിരയല്‍ തുടര്‍പ്രോംപ്റ്റ്"
} }
} }
},
"manageSearch": {
"heading": "Web തിരയൽ സജ്ജമാക്കുക",
"title": "Web തിരയൽ നിയന്ത്രിക്കുക"
} }
} }

View File

@ -204,5 +204,9 @@
"webSearchFollowUpPromptPlaceholder": "您的网页搜索追问提示词" "webSearchFollowUpPromptPlaceholder": "您的网页搜索追问提示词"
} }
} }
},
"manageSearch": {
"heading": "配置网络搜索",
"title": "管理网络搜索"
} }
} }

View File

@ -0,0 +1,27 @@
import { PageAssistContext } from "@/context"
import { Message } from "@/types/message"
import React from "react"
export const PageAssistProvider = ({
children
}: {
children: React.ReactNode
}) => {
const [messages, setMessages] = React.useState<Message[]>([])
const [controller, setController] = React.useState<AbortController | null>(
null
)
return (
<PageAssistContext.Provider
value={{
messages,
setMessages,
controller,
setController
}}>
{children}
</PageAssistContext.Provider>
)
}

View File

@ -1,9 +1,4 @@
import { import { Book, BrainCircuit, Orbit, Share } from "lucide-react"
Book,
BrainCircuit,
Orbit,
Share
} from "lucide-react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link, useLocation } from "react-router-dom" import { Link, useLocation } from "react-router-dom"
import { OllamaIcon } from "../Icons/Ollama" import { OllamaIcon } from "../Icons/Ollama"

26
src/context/index.tsx Normal file
View File

@ -0,0 +1,26 @@
import { Message } from "@/types/message"
import React, { Dispatch, SetStateAction, createContext } from "react"
interface PageAssistContext {
messages: Message[]
setMessages: Dispatch<SetStateAction<Message[]>>
controller: AbortController | null
setController: Dispatch<SetStateAction<AbortController>>
}
export const PageAssistContext = createContext<PageAssistContext>({
messages: [],
setMessages: () => {},
controller: null,
setController: () => {}
})
export const usePageAssist = () => {
const context = React.useContext(PageAssistContext)
if (!context) {
throw new Error("usePageAssist must be used within a PageAssistContext")
}
return context
}

View File

@ -1,7 +1,5 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { MemoryRouter } from "react-router-dom" import { MemoryRouter } from "react-router-dom"
import { ToastContainer } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"
const queryClient = new QueryClient() const queryClient = new QueryClient()
import { ConfigProvider, Empty, theme } from "antd" import { ConfigProvider, Empty, theme } from "antd"
import { StyleProvider } from "@ant-design/cssinjs" import { StyleProvider } from "@ant-design/cssinjs"
@ -9,6 +7,7 @@ import { useDarkMode } from "~/hooks/useDarkmode"
import { OptionRouting } from "~/routes" import { OptionRouting } from "~/routes"
import "~/i18n" import "~/i18n"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { PageAssistProvider } from "@/components/Common/PageAssistProvider"
function IndexOption() { function IndexOption() {
const { mode } = useDarkMode() const { mode } = useDarkMode()
@ -27,12 +26,12 @@ function IndexOption() {
}} }}
description={t("common:noData")} description={t("common:noData")}
/> />
)} )}>
>
<StyleProvider hashPriority="high"> <StyleProvider hashPriority="high">
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<OptionRouting /> <PageAssistProvider>
<ToastContainer /> <OptionRouting />
</PageAssistProvider>
</QueryClientProvider> </QueryClientProvider>
</StyleProvider> </StyleProvider>
</ConfigProvider> </ConfigProvider>

View File

@ -1,14 +1,13 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { MemoryRouter } from "react-router-dom" import { MemoryRouter } from "react-router-dom"
import { SidepanelRouting } from "~/routes" import { SidepanelRouting } from "~/routes"
import { ToastContainer } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"
const queryClient = new QueryClient() const queryClient = new QueryClient()
import { ConfigProvider, Empty, theme } from "antd" import { ConfigProvider, Empty, theme } from "antd"
import { StyleProvider } from "@ant-design/cssinjs" import { StyleProvider } from "@ant-design/cssinjs"
import { useDarkMode } from "~/hooks/useDarkmode" import { useDarkMode } from "~/hooks/useDarkmode"
import "~/i18n" import "~/i18n"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { PageAssistProvider } from "@/components/Common/PageAssistProvider"
function IndexSidepanel() { function IndexSidepanel() {
const { mode } = useDarkMode() const { mode } = useDarkMode()
@ -28,12 +27,12 @@ function IndexSidepanel() {
}} }}
description={t("common:noData")} description={t("common:noData")}
/> />
)} )}>
>
<StyleProvider hashPriority="high"> <StyleProvider hashPriority="high">
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<SidepanelRouting /> <PageAssistProvider>
<ToastContainer /> <SidepanelRouting />
</PageAssistProvider>
</QueryClientProvider> </QueryClientProvider>
</StyleProvider> </StyleProvider>
</ConfigProvider> </ConfigProvider>

View File

@ -0,0 +1,160 @@
import { saveHistory, saveMessage } from "@/libs/db"
import { ChatHistory } from "@/store/option"
export const saveMessageOnError = async ({
e,
history,
setHistory,
image,
userMessage,
botMessage,
historyId,
selectedModel,
setHistoryId,
isRegenerating
}: {
e: any
setHistory: (history: ChatHistory) => void
history: ChatHistory
userMessage: string
image: string
botMessage: string
historyId: string | null
selectedModel: string
setHistoryId: (historyId: string) => void
isRegenerating: boolean
}) => {
if (
e?.name === "AbortError" ||
e?.message === "AbortError" ||
e?.name?.includes("AbortError") ||
e?.message?.includes("AbortError")
) {
setHistory([
...history,
{
role: "user",
content: userMessage,
image
},
{
role: "assistant",
content: botMessage
}
])
if (historyId) {
if (!isRegenerating) {
await saveMessage(
historyId,
selectedModel,
"user",
userMessage,
[image],
[],
1
)
}
await saveMessage(
historyId,
selectedModel,
"assistant",
botMessage,
[],
[],
2
)
} else {
const newHistoryId = await saveHistory(userMessage)
if (!isRegenerating) {
await saveMessage(
newHistoryId.id,
selectedModel,
"user",
userMessage,
[image],
[],
1
)
}
await saveMessage(
newHistoryId.id,
selectedModel,
"assistant",
botMessage,
[],
[],
2
)
setHistoryId(newHistoryId.id)
}
return true
}
return false
}
export const saveMessageOnSuccess = async ({
historyId,
setHistoryId,
isRegenerate,
selectedModel,
message,
image,
fullText,
source
}: {
historyId: string | null
setHistoryId: (historyId: string) => void
isRegenerate: boolean
selectedModel: string | null
message: string
image: string
fullText: string
source: any[]
}) => {
if (historyId) {
if (!isRegenerate) {
await saveMessage(
historyId,
selectedModel,
"user",
message,
[image],
[],
1
)
}
await saveMessage(
historyId,
selectedModel!,
"assistant",
fullText,
[],
source,
2
)
} else {
const newHistoryId = await saveHistory(message)
await saveMessage(
newHistoryId.id,
selectedModel,
"user",
message,
[image],
[],
1
)
await saveMessage(
newHistoryId.id,
selectedModel!,
"assistant",
fullText,
[],
source,
2
)
setHistoryId(newHistoryId.id)
}
}

View File

@ -11,10 +11,9 @@ import { HumanMessage, SystemMessage } from "@langchain/core/messages"
import { useStoreMessageOption } from "~/store/option" import { useStoreMessageOption } from "~/store/option"
import { import {
deleteChatForEdit, deleteChatForEdit,
generateID,
getPromptById, getPromptById,
removeMessageUsingHistoryId, removeMessageUsingHistoryId,
saveHistory,
saveMessage,
updateMessageByIndex updateMessageByIndex
} from "~/libs/db" } from "~/libs/db"
import { useNavigate } from "react-router-dom" import { useNavigate } from "react-router-dom"
@ -22,13 +21,19 @@ import { notification } from "antd"
import { getSystemPromptForWeb } from "~/web/web" import { getSystemPromptForWeb } from "~/web/web"
import { generateHistory } from "@/utils/generate-history" import { generateHistory } from "@/utils/generate-history"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { saveMessageOnError, saveMessageOnSuccess } from "./chat-helper"
import { usePageAssist } from "@/context"
export const useMessageOption = () => { export const useMessageOption = () => {
const { const {
history, controller: abortController,
setController: setAbortController,
messages, messages,
setMessages
} = usePageAssist()
const {
history,
setHistory, setHistory,
setMessages,
setStreaming, setStreaming,
streaming, streaming,
setIsFirstMessage, setIsFirstMessage,
@ -59,8 +64,6 @@ export const useMessageOption = () => {
const navigate = useNavigate() const navigate = useNavigate()
const textareaRef = React.useRef<HTMLTextAreaElement>(null) const textareaRef = React.useRef<HTMLTextAreaElement>(null)
const abortControllerRef = React.useRef<AbortController | null>(null)
const clearChat = () => { const clearChat = () => {
navigate("/") navigate("/")
setMessages([]) setMessages([])
@ -78,14 +81,14 @@ export const useMessageOption = () => {
image: string, image: string,
isRegenerate: boolean, isRegenerate: boolean,
messages: Message[], messages: Message[],
history: ChatHistory history: ChatHistory,
signal: AbortSignal
) => { ) => {
const url = await getOllamaURL() const url = await getOllamaURL()
if (image.length > 0) { if (image.length > 0) {
image = `data:image/jpeg;base64,${image.split(",")[1]}` image = `data:image/jpeg;base64,${image.split(",")[1]}`
} }
abortControllerRef.current = new AbortController()
const ollama = new ChatOllama({ const ollama = new ChatOllama({
model: selectedModel!, model: selectedModel!,
@ -93,6 +96,8 @@ export const useMessageOption = () => {
}) })
let newMessage: Message[] = [] let newMessage: Message[] = []
let generateMessageId = generateID()
if (!isRegenerate) { if (!isRegenerate) {
newMessage = [ newMessage = [
...messages, ...messages,
@ -107,7 +112,8 @@ export const useMessageOption = () => {
isBot: true, isBot: true,
name: selectedModel, name: selectedModel,
message: "▋", message: "▋",
sources: [] sources: [],
id: generateMessageId
} }
] ]
} else { } else {
@ -117,12 +123,14 @@ export const useMessageOption = () => {
isBot: true, isBot: true,
name: selectedModel, name: selectedModel,
message: "▋", message: "▋",
sources: [] sources: [],
id: generateMessageId
} }
] ]
} }
setMessages(newMessage) setMessages(newMessage)
const appendingIndex = newMessage.length - 1 let fullText = ""
let contentToSave = ""
try { try {
setIsSearchingInternet(true) setIsSearchingInternet(true)
@ -195,138 +203,93 @@ export const useMessageOption = () => {
const chunks = await ollama.stream( const chunks = await ollama.stream(
[...applicationChatHistory, humanMessage], [...applicationChatHistory, humanMessage],
{ {
signal: abortControllerRef.current.signal signal: signal
} }
) )
let count = 0 let count = 0
for await (const chunk of chunks) { for await (const chunk of chunks) {
contentToSave += chunk.content
fullText += chunk.content
if (count === 0) { if (count === 0) {
setIsProcessing(true) setIsProcessing(true)
newMessage[appendingIndex].message = chunk.content + "▋"
setMessages(newMessage)
} else {
newMessage[appendingIndex].message =
newMessage[appendingIndex].message.slice(0, -1) +
chunk.content +
"▋"
setMessages(newMessage)
} }
setMessages((prev) => {
return prev.map((message) => {
if (message.id === generateMessageId) {
return {
...message,
message: fullText.slice(0, -1) + "▋"
}
}
return message
})
})
count++ count++
} }
// update the message with the full text
newMessage[appendingIndex].message = newMessage[ setMessages((prev) => {
appendingIndex return prev.map((message) => {
].message.slice(0, -1) if (message.id === generateMessageId) {
return {
newMessage[appendingIndex].sources = source ...message,
message: fullText,
if (!isRegenerate) { sources: source
setHistory([ }
...history,
{
role: "user",
content: message,
image
},
{
role: "assistant",
content: newMessage[appendingIndex].message
} }
]) return message
} else { })
setHistory([ })
...history,
{
role: "assistant",
content: newMessage[appendingIndex].message
}
])
}
if (historyId) { setHistory([
if (!isRegenerate) { ...history,
await saveMessage(historyId, selectedModel!, "user", message, [image]) {
} role: "user",
await saveMessage( content: message,
historyId,
selectedModel!,
"assistant",
newMessage[appendingIndex].message,
[],
source
)
} else {
const newHistoryId = await saveHistory(message)
await saveMessage(newHistoryId.id, selectedModel!, "user", message, [
image image
]) },
await saveMessage( {
newHistoryId.id, role: "assistant",
selectedModel!, content: fullText
"assistant", }
newMessage[appendingIndex].message, ])
[],
source await saveMessageOnSuccess({
) historyId,
setHistoryId(newHistoryId.id) setHistoryId,
} isRegenerate,
selectedModel: selectedModel,
message,
image,
fullText,
source
})
setIsProcessing(false) setIsProcessing(false)
setStreaming(false) setStreaming(false)
} catch (e) { } catch (e) {
//@ts-ignore const errorSave = await saveMessageOnError({
if (e?.name === "AbortError") { e,
newMessage[appendingIndex].message = newMessage[ botMessage: fullText,
appendingIndex history,
].message.slice(0, -1) historyId,
image,
selectedModel,
setHistory,
setHistoryId,
userMessage: message,
isRegenerating: isRegenerate
})
setHistory([ if (!errorSave) {
...history,
{
role: "user",
content: message,
image
},
{
role: "assistant",
content: newMessage[appendingIndex].message
}
])
if (historyId) {
await saveMessage(historyId, selectedModel!, "user", message, [image])
await saveMessage(
historyId,
selectedModel!,
"assistant",
newMessage[appendingIndex].message,
[]
)
} else {
const newHistoryId = await saveHistory(message)
await saveMessage(newHistoryId.id, selectedModel!, "user", message, [
image
])
await saveMessage(
newHistoryId.id,
selectedModel!,
"assistant",
newMessage[appendingIndex].message,
[]
)
setHistoryId(newHistoryId.id)
}
} else {
//@ts-ignore
notification.error({ notification.error({
message: t("error"), message: t("error"),
description: e?.message || t("somethingWentWrong") description: e?.message || t("somethingWentWrong")
}) })
} }
setIsProcessing(false) setIsProcessing(false)
setStreaming(false) setStreaming(false)
} finally {
setAbortController(null)
} }
} }
@ -335,14 +298,14 @@ export const useMessageOption = () => {
image: string, image: string,
isRegenerate: boolean, isRegenerate: boolean,
messages: Message[], messages: Message[],
history: ChatHistory history: ChatHistory,
signal: AbortSignal
) => { ) => {
const url = await getOllamaURL() const url = await getOllamaURL()
if (image.length > 0) { if (image.length > 0) {
image = `data:image/jpeg;base64,${image.split(",")[1]}` image = `data:image/jpeg;base64,${image.split(",")[1]}`
} }
abortControllerRef.current = new AbortController()
const ollama = new ChatOllama({ const ollama = new ChatOllama({
model: selectedModel!, model: selectedModel!,
@ -350,6 +313,8 @@ export const useMessageOption = () => {
}) })
let newMessage: Message[] = [] let newMessage: Message[] = []
let generateMessageId = generateID()
if (!isRegenerate) { if (!isRegenerate) {
newMessage = [ newMessage = [
...messages, ...messages,
@ -364,7 +329,8 @@ export const useMessageOption = () => {
isBot: true, isBot: true,
name: selectedModel, name: selectedModel,
message: "▋", message: "▋",
sources: [] sources: [],
id: generateMessageId
} }
] ]
} else { } else {
@ -374,12 +340,14 @@ export const useMessageOption = () => {
isBot: true, isBot: true,
name: selectedModel, name: selectedModel,
message: "▋", message: "▋",
sources: [] sources: [],
id: generateMessageId
} }
] ]
} }
setMessages(newMessage) setMessages(newMessage)
const appendingIndex = newMessage.length - 1 let fullText = ""
let contentToSave = ""
try { try {
const prompt = await systemPromptForNonRagOption() const prompt = await systemPromptForNonRagOption()
@ -441,132 +409,94 @@ export const useMessageOption = () => {
const chunks = await ollama.stream( const chunks = await ollama.stream(
[...applicationChatHistory, humanMessage], [...applicationChatHistory, humanMessage],
{ {
signal: abortControllerRef.current.signal signal: signal
} }
) )
let count = 0 let count = 0
for await (const chunk of chunks) { for await (const chunk of chunks) {
contentToSave += chunk.content
fullText += chunk.content
if (count === 0) { if (count === 0) {
setIsProcessing(true) setIsProcessing(true)
newMessage[appendingIndex].message = chunk.content + "▋"
setMessages(newMessage)
} else {
newMessage[appendingIndex].message =
newMessage[appendingIndex].message.slice(0, -1) +
chunk.content +
"▋"
setMessages(newMessage)
} }
setMessages((prev) => {
return prev.map((message) => {
if (message.id === generateMessageId) {
return {
...message,
message: fullText.slice(0, -1) + "▋"
}
}
return message
})
})
count++ count++
} }
newMessage[appendingIndex].message = newMessage[ setMessages((prev) => {
appendingIndex return prev.map((message) => {
].message.slice(0, -1) if (message.id === generateMessageId) {
return {
if (!isRegenerate) { ...message,
setHistory([ message: fullText.slice(0, -1)
...history, }
{
role: "user",
content: message,
image
},
{
role: "assistant",
content: newMessage[appendingIndex].message
} }
]) return message
} else { })
setHistory([ })
...history,
{
role: "assistant",
content: newMessage[appendingIndex].message
}
])
}
if (historyId) { setHistory([
if (!isRegenerate) { ...history,
await saveMessage(historyId, selectedModel, "user", message, [image]) {
} role: "user",
await saveMessage( content: message,
historyId,
selectedModel,
"assistant",
newMessage[appendingIndex].message,
[]
)
} else {
const newHistoryId = await saveHistory(message)
await saveMessage(newHistoryId.id, selectedModel, "user", message, [
image image
]) },
await saveMessage( {
newHistoryId.id, role: "assistant",
selectedModel, content: fullText
"assistant", }
newMessage[appendingIndex].message, ])
[]
) await saveMessageOnSuccess({
setHistoryId(newHistoryId.id) historyId,
} setHistoryId,
isRegenerate,
selectedModel: selectedModel,
message,
image,
fullText,
source: []
})
setIsProcessing(false) setIsProcessing(false)
setStreaming(false) setStreaming(false)
setIsProcessing(false)
setStreaming(false)
} catch (e) { } catch (e) {
if (e?.name === "AbortError") { const errorSave = await saveMessageOnError({
newMessage[appendingIndex].message = newMessage[ e,
appendingIndex botMessage: fullText,
].message.slice(0, -1) history,
historyId,
image,
selectedModel,
setHistory,
setHistoryId,
userMessage: message,
isRegenerating: isRegenerate
})
setHistory([ if (!errorSave) {
...history,
{
role: "user",
content: message,
image
},
{
role: "assistant",
content: newMessage[appendingIndex].message
}
])
if (historyId) {
await saveMessage(historyId, selectedModel, "user", message, [image])
await saveMessage(
historyId,
selectedModel,
"assistant",
newMessage[appendingIndex].message,
[]
)
} else {
const newHistoryId = await saveHistory(message)
await saveMessage(newHistoryId.id, selectedModel, "user", message, [
image
])
await saveMessage(
newHistoryId.id,
selectedModel,
"assistant",
newMessage[appendingIndex].message,
[]
)
setHistoryId(newHistoryId.id)
}
} else {
notification.error({ notification.error({
message: t("error"), message: t("error"),
description: e?.message || t("somethingWentWrong") description: e?.message || t("somethingWentWrong")
}) })
} }
setIsProcessing(false) setIsProcessing(false)
setStreaming(false) setStreaming(false)
} finally {
setAbortController(null)
} }
} }
@ -575,22 +505,34 @@ export const useMessageOption = () => {
image, image,
isRegenerate = false, isRegenerate = false,
messages: chatHistory, messages: chatHistory,
memory memory,
controller
}: { }: {
message: string message: string
image: string image: string
isRegenerate?: boolean isRegenerate?: boolean
messages?: Message[] messages?: Message[]
memory?: ChatHistory memory?: ChatHistory
controller?: AbortController
}) => { }) => {
setStreaming(true) setStreaming(true)
let signal: AbortSignal
if (!controller) {
const newController = new AbortController()
signal = newController.signal
setAbortController(newController)
} else {
setAbortController(controller)
signal = controller.signal
}
if (webSearch) { if (webSearch) {
await searchChatMode( await searchChatMode(
message, message,
image, image,
isRegenerate, isRegenerate,
chatHistory || messages, chatHistory || messages,
memory || history memory || history,
signal
) )
} else { } else {
await normalChatMode( await normalChatMode(
@ -598,7 +540,8 @@ export const useMessageOption = () => {
image, image,
isRegenerate, isRegenerate,
chatHistory || messages, chatHistory || messages,
memory || history memory || history,
signal
) )
} }
} }
@ -611,28 +554,29 @@ export const useMessageOption = () => {
} }
if (history.length > 0) { if (history.length > 0) {
const lastMessage = history[history.length - 2] const lastMessage = history[history.length - 2]
let newHistory = history let newHistory = history.slice(0, -2)
let mewMessages = messages let mewMessages = messages
newHistory.pop()
mewMessages.pop() mewMessages.pop()
setHistory(newHistory) setHistory(newHistory)
setMessages(mewMessages) setMessages(mewMessages)
await removeMessageUsingHistoryId(historyId) await removeMessageUsingHistoryId(historyId)
if (lastMessage.role === "user") { if (lastMessage.role === "user") {
const newController = new AbortController()
await onSubmit({ await onSubmit({
message: lastMessage.content, message: lastMessage.content,
image: lastMessage.image || "", image: lastMessage.image || "",
isRegenerate: true, isRegenerate: true,
memory: newHistory memory: newHistory,
controller: newController
}) })
} }
} }
} }
const stopStreamingRequest = () => { const stopStreamingRequest = () => {
if (abortControllerRef.current) { if (abortController) {
abortControllerRef.current.abort() abortController.abort()
abortControllerRef.current = null setAbortController(null)
} }
} }
@ -653,7 +597,6 @@ export const useMessageOption = () => {
message: string, message: string,
isHuman: boolean isHuman: boolean
) => { ) => {
// update message and history by index
let newMessages = messages let newMessages = messages
let newHistory = history let newHistory = history
@ -665,20 +608,21 @@ export const useMessageOption = () => {
} }
const currentHumanMessage = newMessages[index] const currentHumanMessage = newMessages[index]
newMessages[index].message = message
newHistory[index].content = message
const previousMessages = newMessages.slice(0, index + 1) const previousMessages = newMessages.slice(0, index + 1)
setMessages(previousMessages) setMessages(previousMessages)
const previousHistory = newHistory.slice(0, index + 1) const previousHistory = newHistory.slice(0, index)
setHistory(previousHistory) setHistory(previousHistory)
await updateMessageByIndex(historyId, index, message) await updateMessageByIndex(historyId, index, message)
await deleteChatForEdit(historyId, index) await deleteChatForEdit(historyId, index)
const abortController = new AbortController()
await onSubmit({ await onSubmit({
message: message, message: message,
image: currentHumanMessage.images[0] || "", image: currentHumanMessage.images[0] || "",
isRegenerate: true, isRegenerate: true,
messages: previousMessages, messages: previousMessages,
memory: previousHistory memory: previousHistory,
controller: abortController
}) })
} else { } else {
newMessages[index].message = message newMessages[index].message = message

View File

@ -31,7 +31,6 @@ type Message = {
createdAt: number createdAt: number
} }
type Webshare = { type Webshare = {
id: string id: string
title: string title: string
@ -41,7 +40,6 @@ type Webshare = {
createdAt: number createdAt: number
} }
type Prompt = { type Prompt = {
id: string id: string
title: string title: string
@ -125,7 +123,6 @@ export class PageAssitDatabase {
await this.db.remove(history_id) await this.db.remove(history_id)
} }
async getAllPrompts(): Promise<Prompts> { async getAllPrompts(): Promise<Prompts> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.db.get("prompts", (result) => { this.db.get("prompts", (result) => {
@ -146,7 +143,12 @@ export class PageAssitDatabase {
this.db.set({ prompts: newPrompts }) this.db.set({ prompts: newPrompts })
} }
async updatePrompt(id: string, title: string, content: string, is_system: boolean) { async updatePrompt(
id: string,
title: string,
content: string,
is_system: boolean
) {
const prompts = await this.getAllPrompts() const prompts = await this.getAllPrompts()
const newPrompts = prompts.map((prompt) => { const newPrompts = prompts.map((prompt) => {
if (prompt.id === id) { if (prompt.id === id) {
@ -164,7 +166,6 @@ export class PageAssitDatabase {
return prompts.find((prompt) => prompt.id === id) return prompts.find((prompt) => prompt.id === id)
} }
async getWebshare(id: string) { async getWebshare(id: string) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.db.get(id, (result) => { this.db.get(id, (result) => {
@ -173,7 +174,6 @@ export class PageAssitDatabase {
}) })
} }
async getAllWebshares(): Promise<Webshare[]> { async getAllWebshares(): Promise<Webshare[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.db.get("webshares", (result) => { this.db.get("webshares", (result) => {
@ -207,8 +207,7 @@ export class PageAssitDatabase {
} }
} }
export const generateID = () => {
const generateID = () => {
return "pa_xxxx-xxxx-xxx-xxxx".replace(/[x]/g, () => { return "pa_xxxx-xxxx-xxx-xxxx".replace(/[x]/g, () => {
const r = Math.floor(Math.random() * 16) const r = Math.floor(Math.random() * 16)
return r.toString(16) return r.toString(16)
@ -230,11 +229,24 @@ export const saveMessage = async (
role: string, role: string,
content: string, content: string,
images: string[], images: string[],
source?: any[] source?: any[],
time?: number
) => { ) => {
const id = generateID() const id = generateID()
const createdAt = Date.now() let createdAt = Date.now()
const message = { id, history_id, name, role, content, images, createdAt, sources: source } if (time) {
createdAt += time
}
const message = {
id,
history_id,
name,
role,
content,
images,
createdAt,
sources: source
}
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
await db.addMessage(message) await db.addMessage(message)
return message return message
@ -292,19 +304,20 @@ export const removeMessageUsingHistoryId = async (history_id: string) => {
await db.db.set({ [history_id]: chatHistory }) await db.db.set({ [history_id]: chatHistory })
} }
export const getAllPrompts = async () => { export const getAllPrompts = async () => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
return await db.getAllPrompts() return await db.getAllPrompts()
} }
export const updateMessageByIndex = async (
export const updateMessageByIndex = async (history_id: string, index: number, message: string) => { history_id: string,
index: number,
message: string
) => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
const chatHistory = (await db.getChatHistory(history_id)).reverse() const chatHistory = (await db.getChatHistory(history_id)).reverse()
chatHistory[index].content = message chatHistory[index].content = message
await db.db.set({ [history_id]: chatHistory.reverse() }) await db.db.set({ [history_id]: chatHistory.reverse() })
} }
export const deleteChatForEdit = async (history_id: string, index: number) => { export const deleteChatForEdit = async (history_id: string, index: number) => {
@ -315,7 +328,15 @@ export const deleteChatForEdit = async (history_id: string, index: number) => {
await db.db.set({ [history_id]: previousHistory.reverse() }) await db.db.set({ [history_id]: previousHistory.reverse() })
} }
export const savePrompt = async ({ content, title, is_system = false }: { title: string, content: string, is_system: boolean }) => { export const savePrompt = async ({
content,
title,
is_system = false
}: {
title: string
content: string
is_system: boolean
}) => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
const id = generateID() const id = generateID()
const createdAt = Date.now() const createdAt = Date.now()
@ -324,21 +345,28 @@ export const savePrompt = async ({ content, title, is_system = false }: { title:
return prompt return prompt
} }
export const deletePromptById = async (id: string) => { export const deletePromptById = async (id: string) => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
await db.deletePrompt(id) await db.deletePrompt(id)
return id return id
} }
export const updatePrompt = async ({
export const updatePrompt = async ({ content, id, title, is_system }: { id: string, title: string, content: string, is_system: boolean }) => { content,
id,
title,
is_system
}: {
id: string
title: string
content: string
is_system: boolean
}) => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
await db.updatePrompt(id, title, content, is_system) await db.updatePrompt(id, title, content, is_system)
return id return id
} }
export const getPromptById = async (id: string) => { export const getPromptById = async (id: string) => {
if (!id || id.trim() === "") return null if (!id || id.trim() === "") return null
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
@ -354,10 +382,19 @@ export const deleteWebshare = async (id: string) => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
await db.deleteWebshare(id) await db.deleteWebshare(id)
return id return id
} }
export const saveWebshare = async ({ title, url, api_url, share_id }: { title: string, url: string, api_url: string, share_id: string }) => { export const saveWebshare = async ({
title,
url,
api_url,
share_id
}: {
title: string
url: string
api_url: string
share_id: string
}) => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
const id = generateID() const id = generateID()
const createdAt = Date.now() const createdAt = Date.now()
@ -368,7 +405,7 @@ export const saveWebshare = async ({ title, url, api_url, share_id }: { title: s
export const getUserId = async () => { export const getUserId = async () => {
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
const id = await db.getUserID() as string const id = (await db.getUserID()) as string
if (!id || id?.trim() === "") { if (!id || id?.trim() === "") {
const user_id = "user_xxxx-xxxx-xxx-xxxx-xxxx".replace(/[x]/g, () => { const user_id = "user_xxxx-xxxx-xxx-xxxx-xxxx".replace(/[x]/g, () => {
const r = Math.floor(Math.random() * 16) const r = Math.floor(Math.random() * 16)

View File

@ -16,6 +16,7 @@ export type Message = {
sources: any[] sources: any[]
images?: string[] images?: string[]
search?: WebSearch search?: WebSearch
id?: string
} }
export type ChatHistory = { export type ChatHistory = {

18
src/types/message.ts Normal file
View File

@ -0,0 +1,18 @@
type WebSearch = {
search_engine: string
search_url: string
search_query: string
search_results: {
title: string
link: string
}[]
}
export type Message = {
isBot: boolean
name: string
message: string
sources: any[]
images?: string[]
search?: WebSearch
id?: string
}