diff --git a/src/components/Sidepanel/Chat/body.tsx b/src/components/Sidepanel/Chat/body.tsx index 5617970..46daeb5 100644 --- a/src/components/Sidepanel/Chat/body.tsx +++ b/src/components/Sidepanel/Chat/body.tsx @@ -5,7 +5,8 @@ import { EmptySidePanel } from "../Chat/empty" import { useWebUI } from "@/store/webui" export const SidePanelBody = () => { - const { messages, streaming } = useMessage() + const { messages, streaming, regenerateLastMessage, editMessage } = + useMessage() const divRef = React.useRef(null) const { ttsEnabled } = useWebUI() React.useEffect(() => { @@ -18,7 +19,6 @@ export const SidePanelBody = () => { {messages.length === 0 && } {messages.map((message, index) => ( {}} key={index} isBot={message.isBot} message={message.message} @@ -26,15 +26,19 @@ export const SidePanelBody = () => { images={message.images || []} currentMessageIndex={index} totalMessages={messages.length} - onRengerate={() => {}} + onRengerate={regenerateLastMessage} + onEditFormSubmit={(value) => { + editMessage(index, value, !message.isBot) + }} isProcessing={streaming} - hideEditAndRegenerate isTTSEnabled={ttsEnabled} /> ))} - { - import.meta.env.BROWSER === "chrome" ?
:
- } + {import.meta.env.BROWSER === "chrome" ? ( +
+ ) : ( +
+ )}
) diff --git a/src/components/Sidepanel/Chat/form.tsx b/src/components/Sidepanel/Chat/form.tsx index 41afbcb..a5a0a2e 100644 --- a/src/components/Sidepanel/Chat/form.tsx +++ b/src/components/Sidepanel/Chat/form.tsx @@ -23,11 +23,6 @@ export const SidepanelForm = ({ dropedFile }: Props) => { const [typing, setTyping] = React.useState(false) const { t } = useTranslation(["playground", "common"]) - const textAreaFocus = () => { - if (textareaRef.current) { - textareaRef.current.focus() - } - } const form = useForm({ initialValues: { message: "", @@ -48,39 +43,11 @@ export const SidepanelForm = ({ dropedFile }: Props) => { } } } - - React.useEffect(() => { - if (dropedFile) { - onInputChange(dropedFile) + const textAreaFocus = () => { + if (textareaRef.current) { + textareaRef.current.focus() } - }, [dropedFile]) - - useDynamicTextareaSize(textareaRef, form.values.message, 120) - - const { - onSubmit, - selectedModel, - chatMode, - speechToTextLanguage, - stopStreamingRequest - } = useMessage() - const { isListening, start, stop, transcript } = useSpeechRecognition() - - React.useEffect(() => { - if (isListening) { - form.setFieldValue("message", transcript) - } - }, [transcript]) - const { mutateAsync: sendMessage, isPending: isSending } = useMutation({ - mutationFn: onSubmit, - onSuccess: () => { - textAreaFocus() - }, - onError: (error) => { - textAreaFocus() - } - }) - + } const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Process" || e.key === "229") return if ( @@ -116,6 +83,39 @@ export const SidepanelForm = ({ dropedFile }: Props) => { } } + const { + onSubmit, + selectedModel, + chatMode, + speechToTextLanguage, + stopStreamingRequest, + streaming + } = useMessage() + const { isListening, start, stop, transcript } = useSpeechRecognition() + + React.useEffect(() => { + if (dropedFile) { + onInputChange(dropedFile) + } + }, [dropedFile]) + + useDynamicTextareaSize(textareaRef, form.values.message, 120) + + React.useEffect(() => { + if (isListening) { + form.setFieldValue("message", transcript) + } + }, [transcript]) + const { mutateAsync: sendMessage, isPending: isSending } = useMutation({ + mutationFn: onSubmit, + onSuccess: () => { + textAreaFocus() + }, + onError: (error) => { + textAreaFocus() + } + }) + return (
{ - {!isSending ? ( + {!streaming ? ( { setCurrentURL(url) isAlreadyExistEmbedding = keepTrackOfEmbedding[currentURL] } else { - isAlreadyExistEmbedding = keepTrackOfEmbedding[currentURL] - embedURL = currentURL + const { content: html, url, type, pdf } = await getDataFromCurrentTab() + if (currentURL !== url) { + embedHTML = html + embedURL = url + embedType = type + embedPDF = pdf + setCurrentURL(url) + } else { + embedHTML = html + embedURL = currentURL + embedType = type + embedPDF = pdf + } + isAlreadyExistEmbedding = keepTrackOfEmbedding[url] } setMessages(newMessage) @@ -157,6 +173,7 @@ export const useMessage = () => { try { if (isAlreadyExistEmbedding) { vectorstore = isAlreadyExistEmbedding + console.log("Embedding already exist") } else { vectorstore = await memoryEmbedding({ html: embedHTML, @@ -168,6 +185,8 @@ export const useMessage = () => { type: embedType, url: embedURL }) + + console.log("Embedding created") } let query = message const { ragPrompt: systemPrompt, ragQuestionPrompt: questionPrompt } = @@ -202,7 +221,7 @@ export const useMessage = () => { url: "" } }) - // message = message.trim().replaceAll("\n", " ") + // message = message.trim().replaceAll("\n", " ") let humanMessage = new HumanMessage({ content: [ @@ -478,8 +497,6 @@ export const useMessage = () => { setIsProcessing(false) setStreaming(false) - setIsProcessing(false) - setStreaming(false) } catch (e) { const errorSave = await saveMessageOnError({ e, @@ -509,17 +526,38 @@ export const useMessage = () => { const onSubmit = async ({ message, - image + image, + isRegenerate, + controller, + memory, + messages: chatHistory }: { message: string image: string + isRegenerate?: boolean + messages?: Message[] + memory?: ChatHistory + controller?: AbortController }) => { - const newController = new AbortController() - let signal = newController.signal - setAbortController(newController) + let signal: AbortSignal + if (!controller) { + const newController = new AbortController() + signal = newController.signal + setAbortController(newController) + } else { + setAbortController(controller) + signal = controller.signal + } if (chatMode === "normal") { - await normalChatMode(message, image, false, messages, history, signal) + await normalChatMode( + message, + image, + isRegenerate, + chatHistory || messages, + memory || history, + signal + ) } else { const newEmbeddingController = new AbortController() let embeddingSignal = newEmbeddingController.signal @@ -527,9 +565,9 @@ export const useMessage = () => { await chatWithWebsiteMode( message, image, - false, - messages, - history, + isRegenerate, + chatHistory || messages, + memory || history, signal, embeddingSignal ) @@ -548,9 +586,68 @@ export const useMessage = () => { setAbortController(null) } } + + const editMessage = async ( + index: number, + message: string, + isHuman: boolean + ) => { + let newMessages = messages + let newHistory = history + + if (isHuman) { + const currentHumanMessage = newMessages[index] + newMessages[index].message = message + const previousMessages = newMessages.slice(0, index + 1) + setMessages(previousMessages) + 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, + controller: abortController + }) + } else { + newMessages[index].message = message + setMessages(newMessages) + newHistory[index].content = message + setHistory(newHistory) + await updateMessageByIndex(historyId, index, message) + } + } + + const regenerateLastMessage = async () => { + if (history.length > 0) { + const lastMessage = history[history.length - 2] + let newHistory = history.slice(0, -2) + let mewMessages = messages + 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, + controller: newController + }) + } + } + } + return { messages, setMessages, + editMessage, onSubmit, setStreaming, streaming, @@ -569,6 +666,7 @@ export const useMessage = () => { setChatMode, isEmbedding, speechToTextLanguage, - setSpeechToTextLanguage + setSpeechToTextLanguage, + regenerateLastMessage } }