From ea56a2ffa29d690fb105a0a5aedb044778850abb Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sun, 31 Mar 2024 00:36:12 +0530 Subject: [PATCH] Add localization for manage search feature --- src/assets/locale/en/settings.json | 4 + src/assets/locale/ja-JP/settings.json | 4 + src/assets/locale/ml/settings.json | 4 + src/assets/locale/zh/settings.json | 4 + src/components/Common/PageAssistProvider.tsx | 27 ++ .../Layouts/SettingsOptionLayout.tsx | 7 +- src/context/index.tsx | 26 ++ src/entries/options/App.tsx | 11 +- src/entries/sidepanel/App.tsx | 11 +- src/hooks/chat-helper/index.ts | 160 +++++++ src/hooks/useMessageOption.tsx | 422 ++++++++---------- src/libs/db.ts | 85 +++- src/store/option.tsx | 1 + src/types/message.ts | 18 + 14 files changed, 503 insertions(+), 281 deletions(-) create mode 100644 src/components/Common/PageAssistProvider.tsx create mode 100644 src/context/index.tsx create mode 100644 src/hooks/chat-helper/index.ts create mode 100644 src/types/message.ts diff --git a/src/assets/locale/en/settings.json b/src/assets/locale/en/settings.json index 40e5c58..44e3c6e 100644 --- a/src/assets/locale/en/settings.json +++ b/src/assets/locale/en/settings.json @@ -203,5 +203,9 @@ "webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt" } } + }, + "manageSearch": { + "title": "Manage Web Search", + "heading": "Configure Web Search" } } \ No newline at end of file diff --git a/src/assets/locale/ja-JP/settings.json b/src/assets/locale/ja-JP/settings.json index 71007ad..ea7f090 100644 --- a/src/assets/locale/ja-JP/settings.json +++ b/src/assets/locale/ja-JP/settings.json @@ -203,5 +203,9 @@ "webSearchFollowUpPromptPlaceholder": "Web検索フォローアッププロンプト" } } + }, + "manageSearch": { + "title": "Web検索の管理", + "heading": "Web検索を設定する" } } \ No newline at end of file diff --git a/src/assets/locale/ml/settings.json b/src/assets/locale/ml/settings.json index d896f45..82dd19b 100644 --- a/src/assets/locale/ml/settings.json +++ b/src/assets/locale/ml/settings.json @@ -203,5 +203,9 @@ "webSearchFollowUpPromptPlaceholder": "നിങ്ങളുടെ വെബ് തിരയല്‍ തുടര്‍പ്രോംപ്റ്റ്" } } + }, + "manageSearch": { + "heading": "Web തിരയൽ സജ്ജമാക്കുക", + "title": "Web തിരയൽ നിയന്ത്രിക്കുക" } } \ No newline at end of file diff --git a/src/assets/locale/zh/settings.json b/src/assets/locale/zh/settings.json index 251b07e..6ac32bf 100644 --- a/src/assets/locale/zh/settings.json +++ b/src/assets/locale/zh/settings.json @@ -204,5 +204,9 @@ "webSearchFollowUpPromptPlaceholder": "您的网页搜索追问提示词" } } + }, + "manageSearch": { + "heading": "配置网络搜索", + "title": "管理网络搜索" } } \ No newline at end of file diff --git a/src/components/Common/PageAssistProvider.tsx b/src/components/Common/PageAssistProvider.tsx new file mode 100644 index 0000000..fb75f83 --- /dev/null +++ b/src/components/Common/PageAssistProvider.tsx @@ -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([]) + const [controller, setController] = React.useState( + null + ) + + return ( + + {children} + + ) +} diff --git a/src/components/Layouts/SettingsOptionLayout.tsx b/src/components/Layouts/SettingsOptionLayout.tsx index de68569..6d83d33 100644 --- a/src/components/Layouts/SettingsOptionLayout.tsx +++ b/src/components/Layouts/SettingsOptionLayout.tsx @@ -1,9 +1,4 @@ -import { - Book, - BrainCircuit, - Orbit, - Share -} from "lucide-react" +import { Book, BrainCircuit, Orbit, Share } from "lucide-react" import { useTranslation } from "react-i18next" import { Link, useLocation } from "react-router-dom" import { OllamaIcon } from "../Icons/Ollama" diff --git a/src/context/index.tsx b/src/context/index.tsx new file mode 100644 index 0000000..7e91bae --- /dev/null +++ b/src/context/index.tsx @@ -0,0 +1,26 @@ +import { Message } from "@/types/message" +import React, { Dispatch, SetStateAction, createContext } from "react" + +interface PageAssistContext { + messages: Message[] + setMessages: Dispatch> + + controller: AbortController | null + setController: Dispatch> +} + +export const PageAssistContext = createContext({ + 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 +} diff --git a/src/entries/options/App.tsx b/src/entries/options/App.tsx index b0221ef..f78a803 100644 --- a/src/entries/options/App.tsx +++ b/src/entries/options/App.tsx @@ -1,7 +1,5 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { MemoryRouter } from "react-router-dom" -import { ToastContainer } from "react-toastify" -import "react-toastify/dist/ReactToastify.css" const queryClient = new QueryClient() import { ConfigProvider, Empty, theme } from "antd" import { StyleProvider } from "@ant-design/cssinjs" @@ -9,6 +7,7 @@ import { useDarkMode } from "~/hooks/useDarkmode" import { OptionRouting } from "~/routes" import "~/i18n" import { useTranslation } from "react-i18next" +import { PageAssistProvider } from "@/components/Common/PageAssistProvider" function IndexOption() { const { mode } = useDarkMode() @@ -27,12 +26,12 @@ function IndexOption() { }} description={t("common:noData")} /> - )} - > + )}> - - + + + diff --git a/src/entries/sidepanel/App.tsx b/src/entries/sidepanel/App.tsx index 26ce815..495d6fd 100644 --- a/src/entries/sidepanel/App.tsx +++ b/src/entries/sidepanel/App.tsx @@ -1,14 +1,13 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { MemoryRouter } from "react-router-dom" import { SidepanelRouting } from "~/routes" -import { ToastContainer } from "react-toastify" -import "react-toastify/dist/ReactToastify.css" const queryClient = new QueryClient() import { ConfigProvider, Empty, theme } from "antd" import { StyleProvider } from "@ant-design/cssinjs" import { useDarkMode } from "~/hooks/useDarkmode" import "~/i18n" import { useTranslation } from "react-i18next" +import { PageAssistProvider } from "@/components/Common/PageAssistProvider" function IndexSidepanel() { const { mode } = useDarkMode() @@ -28,12 +27,12 @@ function IndexSidepanel() { }} description={t("common:noData")} /> - )} - > + )}> - - + + + diff --git a/src/hooks/chat-helper/index.ts b/src/hooks/chat-helper/index.ts new file mode 100644 index 0000000..51d320c --- /dev/null +++ b/src/hooks/chat-helper/index.ts @@ -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) + } +} diff --git a/src/hooks/useMessageOption.tsx b/src/hooks/useMessageOption.tsx index d5e49b1..f0b0d63 100644 --- a/src/hooks/useMessageOption.tsx +++ b/src/hooks/useMessageOption.tsx @@ -11,10 +11,9 @@ import { HumanMessage, SystemMessage } from "@langchain/core/messages" import { useStoreMessageOption } from "~/store/option" import { deleteChatForEdit, + generateID, getPromptById, removeMessageUsingHistoryId, - saveHistory, - saveMessage, updateMessageByIndex } from "~/libs/db" import { useNavigate } from "react-router-dom" @@ -22,13 +21,19 @@ import { notification } from "antd" import { getSystemPromptForWeb } from "~/web/web" import { generateHistory } from "@/utils/generate-history" import { useTranslation } from "react-i18next" +import { saveMessageOnError, saveMessageOnSuccess } from "./chat-helper" +import { usePageAssist } from "@/context" export const useMessageOption = () => { const { - history, + controller: abortController, + setController: setAbortController, messages, + setMessages + } = usePageAssist() + const { + history, setHistory, - setMessages, setStreaming, streaming, setIsFirstMessage, @@ -59,8 +64,6 @@ export const useMessageOption = () => { const navigate = useNavigate() const textareaRef = React.useRef(null) - const abortControllerRef = React.useRef(null) - const clearChat = () => { navigate("/") setMessages([]) @@ -78,14 +81,14 @@ export const useMessageOption = () => { image: string, isRegenerate: boolean, messages: Message[], - history: ChatHistory + history: ChatHistory, + signal: AbortSignal ) => { const url = await getOllamaURL() if (image.length > 0) { image = `data:image/jpeg;base64,${image.split(",")[1]}` } - abortControllerRef.current = new AbortController() const ollama = new ChatOllama({ model: selectedModel!, @@ -93,6 +96,8 @@ export const useMessageOption = () => { }) let newMessage: Message[] = [] + let generateMessageId = generateID() + if (!isRegenerate) { newMessage = [ ...messages, @@ -107,7 +112,8 @@ export const useMessageOption = () => { isBot: true, name: selectedModel, message: "▋", - sources: [] + sources: [], + id: generateMessageId } ] } else { @@ -117,12 +123,14 @@ export const useMessageOption = () => { isBot: true, name: selectedModel, message: "▋", - sources: [] + sources: [], + id: generateMessageId } ] } setMessages(newMessage) - const appendingIndex = newMessage.length - 1 + let fullText = "" + let contentToSave = "" try { setIsSearchingInternet(true) @@ -195,138 +203,93 @@ export const useMessageOption = () => { const chunks = await ollama.stream( [...applicationChatHistory, humanMessage], { - signal: abortControllerRef.current.signal + signal: signal } ) let count = 0 for await (const chunk of chunks) { + contentToSave += chunk.content + fullText += chunk.content if (count === 0) { 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++ } - - newMessage[appendingIndex].message = newMessage[ - appendingIndex - ].message.slice(0, -1) - - newMessage[appendingIndex].sources = source - - if (!isRegenerate) { - setHistory([ - ...history, - { - role: "user", - content: message, - image - }, - { - role: "assistant", - content: newMessage[appendingIndex].message + // update the message with the full text + setMessages((prev) => { + return prev.map((message) => { + if (message.id === generateMessageId) { + return { + ...message, + message: fullText, + sources: source + } } - ]) - } else { - setHistory([ - ...history, - { - role: "assistant", - content: newMessage[appendingIndex].message - } - ]) - } + return message + }) + }) - if (historyId) { - if (!isRegenerate) { - await saveMessage(historyId, selectedModel!, "user", message, [image]) - } - await saveMessage( - historyId, - selectedModel!, - "assistant", - newMessage[appendingIndex].message, - [], - source - ) - } else { - const newHistoryId = await saveHistory(message) - await saveMessage(newHistoryId.id, selectedModel!, "user", message, [ + setHistory([ + ...history, + { + role: "user", + content: message, image - ]) - await saveMessage( - newHistoryId.id, - selectedModel!, - "assistant", - newMessage[appendingIndex].message, - [], - source - ) - setHistoryId(newHistoryId.id) - } + }, + { + role: "assistant", + content: fullText + } + ]) + + await saveMessageOnSuccess({ + historyId, + setHistoryId, + isRegenerate, + selectedModel: selectedModel, + message, + image, + fullText, + source + }) setIsProcessing(false) setStreaming(false) } catch (e) { - //@ts-ignore - if (e?.name === "AbortError") { - newMessage[appendingIndex].message = newMessage[ - appendingIndex - ].message.slice(0, -1) + const errorSave = await saveMessageOnError({ + e, + botMessage: fullText, + history, + historyId, + image, + selectedModel, + setHistory, + setHistoryId, + userMessage: message, + isRegenerating: isRegenerate + }) - setHistory([ - ...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 + if (!errorSave) { notification.error({ message: t("error"), description: e?.message || t("somethingWentWrong") }) } - setIsProcessing(false) setStreaming(false) + } finally { + setAbortController(null) } } @@ -335,14 +298,14 @@ export const useMessageOption = () => { image: string, isRegenerate: boolean, messages: Message[], - history: ChatHistory + history: ChatHistory, + signal: AbortSignal ) => { const url = await getOllamaURL() if (image.length > 0) { image = `data:image/jpeg;base64,${image.split(",")[1]}` } - abortControllerRef.current = new AbortController() const ollama = new ChatOllama({ model: selectedModel!, @@ -350,6 +313,8 @@ export const useMessageOption = () => { }) let newMessage: Message[] = [] + let generateMessageId = generateID() + if (!isRegenerate) { newMessage = [ ...messages, @@ -364,7 +329,8 @@ export const useMessageOption = () => { isBot: true, name: selectedModel, message: "▋", - sources: [] + sources: [], + id: generateMessageId } ] } else { @@ -374,12 +340,14 @@ export const useMessageOption = () => { isBot: true, name: selectedModel, message: "▋", - sources: [] + sources: [], + id: generateMessageId } ] } setMessages(newMessage) - const appendingIndex = newMessage.length - 1 + let fullText = "" + let contentToSave = "" try { const prompt = await systemPromptForNonRagOption() @@ -441,132 +409,94 @@ export const useMessageOption = () => { const chunks = await ollama.stream( [...applicationChatHistory, humanMessage], { - signal: abortControllerRef.current.signal + signal: signal } ) let count = 0 for await (const chunk of chunks) { + contentToSave += chunk.content + fullText += chunk.content if (count === 0) { 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++ } - newMessage[appendingIndex].message = newMessage[ - appendingIndex - ].message.slice(0, -1) - - if (!isRegenerate) { - setHistory([ - ...history, - { - role: "user", - content: message, - image - }, - { - role: "assistant", - content: newMessage[appendingIndex].message + setMessages((prev) => { + return prev.map((message) => { + if (message.id === generateMessageId) { + return { + ...message, + message: fullText.slice(0, -1) + } } - ]) - } else { - setHistory([ - ...history, - { - role: "assistant", - content: newMessage[appendingIndex].message - } - ]) - } + return message + }) + }) - if (historyId) { - if (!isRegenerate) { - 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, [ + setHistory([ + ...history, + { + role: "user", + content: message, image - ]) - await saveMessage( - newHistoryId.id, - selectedModel, - "assistant", - newMessage[appendingIndex].message, - [] - ) - setHistoryId(newHistoryId.id) - } + }, + { + role: "assistant", + content: fullText + } + ]) + + await saveMessageOnSuccess({ + historyId, + setHistoryId, + isRegenerate, + selectedModel: selectedModel, + message, + image, + fullText, + source: [] + }) setIsProcessing(false) setStreaming(false) + setIsProcessing(false) + setStreaming(false) } catch (e) { - if (e?.name === "AbortError") { - newMessage[appendingIndex].message = newMessage[ - appendingIndex - ].message.slice(0, -1) + const errorSave = await saveMessageOnError({ + e, + botMessage: fullText, + history, + historyId, + image, + selectedModel, + setHistory, + setHistoryId, + userMessage: message, + isRegenerating: isRegenerate + }) - setHistory([ - ...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 { + if (!errorSave) { notification.error({ message: t("error"), description: e?.message || t("somethingWentWrong") }) } - setIsProcessing(false) setStreaming(false) + } finally { + setAbortController(null) } } @@ -575,22 +505,34 @@ export const useMessageOption = () => { image, isRegenerate = false, messages: chatHistory, - memory + memory, + controller }: { message: string image: string isRegenerate?: boolean messages?: Message[] memory?: ChatHistory + controller?: AbortController }) => { setStreaming(true) + let signal: AbortSignal + if (!controller) { + const newController = new AbortController() + signal = newController.signal + setAbortController(newController) + } else { + setAbortController(controller) + signal = controller.signal + } if (webSearch) { await searchChatMode( message, image, isRegenerate, chatHistory || messages, - memory || history + memory || history, + signal ) } else { await normalChatMode( @@ -598,7 +540,8 @@ export const useMessageOption = () => { image, isRegenerate, chatHistory || messages, - memory || history + memory || history, + signal ) } } @@ -611,28 +554,29 @@ export const useMessageOption = () => { } if (history.length > 0) { const lastMessage = history[history.length - 2] - let newHistory = history + let newHistory = history.slice(0, -2) let mewMessages = messages - newHistory.pop() mewMessages.pop() setHistory(newHistory) setMessages(mewMessages) await removeMessageUsingHistoryId(historyId) if (lastMessage.role === "user") { + const newController = new AbortController() await onSubmit({ message: lastMessage.content, image: lastMessage.image || "", isRegenerate: true, - memory: newHistory + memory: newHistory, + controller: newController }) } } } const stopStreamingRequest = () => { - if (abortControllerRef.current) { - abortControllerRef.current.abort() - abortControllerRef.current = null + if (abortController) { + abortController.abort() + setAbortController(null) } } @@ -653,7 +597,6 @@ export const useMessageOption = () => { message: string, isHuman: boolean ) => { - // update message and history by index let newMessages = messages let newHistory = history @@ -665,20 +608,21 @@ export const useMessageOption = () => { } const currentHumanMessage = newMessages[index] - newMessages[index].message = message - newHistory[index].content = message + const previousMessages = newMessages.slice(0, index + 1) setMessages(previousMessages) - const previousHistory = newHistory.slice(0, index + 1) + const previousHistory = newHistory.slice(0, index) setHistory(previousHistory) await updateMessageByIndex(historyId, index, message) await deleteChatForEdit(historyId, index) + const abortController = new AbortController() await onSubmit({ message: message, image: currentHumanMessage.images[0] || "", isRegenerate: true, messages: previousMessages, - memory: previousHistory + memory: previousHistory, + controller: abortController }) } else { newMessages[index].message = message diff --git a/src/libs/db.ts b/src/libs/db.ts index 095c865..bc4d851 100644 --- a/src/libs/db.ts +++ b/src/libs/db.ts @@ -31,7 +31,6 @@ type Message = { createdAt: number } - type Webshare = { id: string title: string @@ -41,7 +40,6 @@ type Webshare = { createdAt: number } - type Prompt = { id: string title: string @@ -125,7 +123,6 @@ export class PageAssitDatabase { await this.db.remove(history_id) } - async getAllPrompts(): Promise { return new Promise((resolve, reject) => { this.db.get("prompts", (result) => { @@ -146,7 +143,12 @@ export class PageAssitDatabase { 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 newPrompts = prompts.map((prompt) => { if (prompt.id === id) { @@ -164,7 +166,6 @@ export class PageAssitDatabase { return prompts.find((prompt) => prompt.id === id) } - async getWebshare(id: string) { return new Promise((resolve, reject) => { this.db.get(id, (result) => { @@ -173,7 +174,6 @@ export class PageAssitDatabase { }) } - async getAllWebshares(): Promise { return new Promise((resolve, reject) => { this.db.get("webshares", (result) => { @@ -207,8 +207,7 @@ export class PageAssitDatabase { } } - -const generateID = () => { +export const generateID = () => { return "pa_xxxx-xxxx-xxx-xxxx".replace(/[x]/g, () => { const r = Math.floor(Math.random() * 16) return r.toString(16) @@ -230,11 +229,24 @@ export const saveMessage = async ( role: string, content: string, images: string[], - source?: any[] + source?: any[], + time?: number ) => { const id = generateID() - const createdAt = Date.now() - const message = { id, history_id, name, role, content, images, createdAt, sources: source } + let createdAt = Date.now() + if (time) { + createdAt += time + } + const message = { + id, + history_id, + name, + role, + content, + images, + createdAt, + sources: source + } const db = new PageAssitDatabase() await db.addMessage(message) return message @@ -292,19 +304,20 @@ export const removeMessageUsingHistoryId = async (history_id: string) => { await db.db.set({ [history_id]: chatHistory }) } - export const getAllPrompts = async () => { const db = new PageAssitDatabase() return await db.getAllPrompts() } - -export const updateMessageByIndex = async (history_id: string, index: number, message: string) => { +export const updateMessageByIndex = async ( + history_id: string, + index: number, + message: string +) => { const db = new PageAssitDatabase() const chatHistory = (await db.getChatHistory(history_id)).reverse() chatHistory[index].content = message await db.db.set({ [history_id]: chatHistory.reverse() }) - } 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() }) } -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 id = generateID() const createdAt = Date.now() @@ -324,21 +345,28 @@ export const savePrompt = async ({ content, title, is_system = false }: { title: return prompt } - export const deletePromptById = async (id: string) => { const db = new PageAssitDatabase() await db.deletePrompt(id) return id } - -export const updatePrompt = async ({ content, id, title, is_system }: { id: string, title: string, content: string, is_system: boolean }) => { +export const updatePrompt = async ({ + content, + id, + title, + is_system +}: { + id: string + title: string + content: string + is_system: boolean +}) => { const db = new PageAssitDatabase() await db.updatePrompt(id, title, content, is_system) return id } - export const getPromptById = async (id: string) => { if (!id || id.trim() === "") return null const db = new PageAssitDatabase() @@ -354,10 +382,19 @@ export const deleteWebshare = async (id: string) => { const db = new PageAssitDatabase() await db.deleteWebshare(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 id = generateID() const createdAt = Date.now() @@ -368,7 +405,7 @@ export const saveWebshare = async ({ title, url, api_url, share_id }: { title: s export const getUserId = async () => { const db = new PageAssitDatabase() - const id = await db.getUserID() as string + const id = (await db.getUserID()) as string if (!id || id?.trim() === "") { const user_id = "user_xxxx-xxxx-xxx-xxxx-xxxx".replace(/[x]/g, () => { const r = Math.floor(Math.random() * 16) @@ -378,4 +415,4 @@ export const getUserId = async () => { return user_id } return id -} \ No newline at end of file +} diff --git a/src/store/option.tsx b/src/store/option.tsx index 51e41c1..0de6c80 100644 --- a/src/store/option.tsx +++ b/src/store/option.tsx @@ -16,6 +16,7 @@ export type Message = { sources: any[] images?: string[] search?: WebSearch + id?: string } export type ChatHistory = { diff --git a/src/types/message.ts b/src/types/message.ts new file mode 100644 index 0000000..66e954e --- /dev/null +++ b/src/types/message.ts @@ -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 + } \ No newline at end of file