feat: add save and send functionality for user message
Adds a "Save" button to the edit message form in Playground, allowing users to save changes without immediately submitting them. This also introduces a new `isSend` flag to the `onEditFormSubmit` prop, enabling developers to control whether a message should be sent immediately or saved for later submission. This enhances flexibility and user control during the message editing process.
This commit is contained in:
parent
31ca246407
commit
65ba2ff898
@ -8,20 +8,8 @@ import rehypeKatex from "rehype-katex"
|
|||||||
import "property-information"
|
import "property-information"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { CodeBlock } from "./CodeBlock"
|
import { CodeBlock } from "./CodeBlock"
|
||||||
export const preprocessLaTeX = (content: string) => {
|
import { preprocessLaTeX } from "@/utils/latex"
|
||||||
// Replace block-level LaTeX delimiters \[ \] with $$ $$
|
|
||||||
|
|
||||||
const blockProcessedContent = content.replace(
|
|
||||||
/\\\[(.*?)\\\]/gs,
|
|
||||||
(_, equation) => `$$${equation}$$`
|
|
||||||
)
|
|
||||||
// Replace inline LaTeX delimiters \( \) with $ $
|
|
||||||
const inlineProcessedContent = blockProcessedContent.replace(
|
|
||||||
/\\\((.*?)\\\)/gs,
|
|
||||||
(_, equation) => `$${equation}$`
|
|
||||||
)
|
|
||||||
return inlineProcessedContent
|
|
||||||
}
|
|
||||||
function Markdown({
|
function Markdown({
|
||||||
message,
|
message,
|
||||||
className = "prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark"
|
className = "prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark"
|
||||||
|
@ -5,7 +5,7 @@ import useDynamicTextareaSize from "~/hooks/useDynamicTextareaSize"
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: string
|
value: string
|
||||||
onSumbit: (value: string) => void
|
onSumbit: (value: string, isSend: boolean) => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
isBot: boolean
|
isBot: boolean
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ export const EditMessageForm = (props: Props) => {
|
|||||||
onSubmit={form.onSubmit((data) => {
|
onSubmit={form.onSubmit((data) => {
|
||||||
if (isComposing) return
|
if (isComposing) return
|
||||||
props.onClose()
|
props.onClose()
|
||||||
props.onSumbit(data.message)
|
props.onSumbit(data.message, true)
|
||||||
})}
|
})}
|
||||||
className="flex flex-col gap-2">
|
className="flex flex-col gap-2">
|
||||||
<textarea
|
<textarea
|
||||||
@ -46,19 +46,39 @@ export const EditMessageForm = (props: Props) => {
|
|||||||
ref={textareaRef}
|
ref={textareaRef}
|
||||||
className="w-full bg-transparent focus-within:outline-none focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100"
|
className="w-full bg-transparent focus-within:outline-none focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100"
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-center space-x-2 mt-2">
|
<div className="flex flex-wrap gap-2 mt-2">
|
||||||
<button
|
<div
|
||||||
aria-label={t("save")}
|
className={`w-full flex ${
|
||||||
className="bg-black px-2.5 py-2 rounded-lg text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-900">
|
!props.isBot ? "justify-between" : "justify-end"
|
||||||
{props.isBot ? t("save") : t("saveAndSubmit")}
|
}`}>
|
||||||
</button>
|
{!props.isBot && (
|
||||||
<button
|
<button
|
||||||
onClick={props.onClose}
|
type="button"
|
||||||
aria-label={t("cancel")}
|
onClick={() => {
|
||||||
className="border dark:border-gray-600 px-2.5 py-2 rounded-lg text-gray-700 dark:text-gray-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-100 dark:hover:bg-gray-900">
|
props.onSumbit(form.values.message, false)
|
||||||
{t("cancel")}
|
props.onClose()
|
||||||
</button>
|
}}
|
||||||
</div>
|
aria-label={t("save")}
|
||||||
|
className="border border-gray-600 px-2 py-1.5 rounded-lg text-gray-700 dark:text-gray-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-100 dark:hover:bg-gray-900 text-sm">
|
||||||
|
{t("save")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<button
|
||||||
|
aria-label={t("save")}
|
||||||
|
className="bg-black px-2 py-1.5 rounded-lg text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-900 text-sm">
|
||||||
|
{props.isBot ? t("save") : t("saveAndSubmit")}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={props.onClose}
|
||||||
|
aria-label={t("cancel")}
|
||||||
|
className="border dark:border-gray-600 px-2 py-1.5 rounded-lg text-gray-700 dark:text-gray-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-100 dark:hover:bg-gray-900 text-sm">
|
||||||
|
{t("cancel")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>{" "}
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ type Props = {
|
|||||||
currentMessageIndex: number
|
currentMessageIndex: number
|
||||||
totalMessages: number
|
totalMessages: number
|
||||||
onRengerate: () => void
|
onRengerate: () => void
|
||||||
onEditFormSubmit: (value: string) => void
|
onEditFormSubmit: (value: string, isSend: boolean) => void
|
||||||
isProcessing: boolean
|
isProcessing: boolean
|
||||||
webSearch?: {}
|
webSearch?: {}
|
||||||
isSearchingInternet?: boolean
|
isSearchingInternet?: boolean
|
||||||
|
@ -46,8 +46,8 @@ export const PlaygroundChat = () => {
|
|||||||
isProcessing={streaming}
|
isProcessing={streaming}
|
||||||
isSearchingInternet={isSearchingInternet}
|
isSearchingInternet={isSearchingInternet}
|
||||||
sources={message.sources}
|
sources={message.sources}
|
||||||
onEditFormSubmit={(value) => {
|
onEditFormSubmit={(value, isSend) => {
|
||||||
editMessage(index, value, !message.isBot)
|
editMessage(index, value, !message.isBot, isSend)
|
||||||
}}
|
}}
|
||||||
onSourceClick={(data) => {
|
onSourceClick={(data) => {
|
||||||
setSource(data)
|
setSource(data)
|
||||||
|
@ -86,11 +86,10 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
|
|||||||
placeholder={t("generalSettings.tts.ttsVoice.placeholder")}
|
placeholder={t("generalSettings.tts.ttsVoice.placeholder")}
|
||||||
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
|
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
|
||||||
options={data?.browserTTSVoices?.map(
|
options={data?.browserTTSVoices?.map(
|
||||||
(voice) =>
|
(voice) => ({
|
||||||
({
|
label: `${voice.voiceName} - ${voice.lang}`.trim(),
|
||||||
label: `${voice.voiceName} - ${voice.lang}`.trim(),
|
value: voice.voiceName
|
||||||
value: voice.voiceName
|
})
|
||||||
}) || []
|
|
||||||
)}
|
)}
|
||||||
{...form.getInputProps("voice")}
|
{...form.getInputProps("voice")}
|
||||||
/>
|
/>
|
||||||
|
@ -910,12 +910,14 @@ export const useMessageOption = () => {
|
|||||||
const editMessage = async (
|
const editMessage = async (
|
||||||
index: number,
|
index: number,
|
||||||
message: string,
|
message: string,
|
||||||
isHuman: boolean
|
isHuman: boolean,
|
||||||
|
isSend: boolean
|
||||||
) => {
|
) => {
|
||||||
let newMessages = messages
|
let newMessages = messages
|
||||||
let newHistory = history
|
let newHistory = history
|
||||||
|
|
||||||
if (isHuman) {
|
// if human message and send then only trigger the submit
|
||||||
|
if (isHuman && isSend) {
|
||||||
const isOk = validateBeforeSubmit()
|
const isOk = validateBeforeSubmit()
|
||||||
|
|
||||||
if (!isOk) {
|
if (!isOk) {
|
||||||
@ -939,13 +941,13 @@ export const useMessageOption = () => {
|
|||||||
memory: previousHistory,
|
memory: previousHistory,
|
||||||
controller: abortController
|
controller: abortController
|
||||||
})
|
})
|
||||||
} else {
|
return
|
||||||
newMessages[index].message = message
|
|
||||||
setMessages(newMessages)
|
|
||||||
newHistory[index].content = message
|
|
||||||
setHistory(newHistory)
|
|
||||||
await updateMessageByIndex(historyId, index, message)
|
|
||||||
}
|
}
|
||||||
|
newMessages[index].message = message
|
||||||
|
setMessages(newMessages)
|
||||||
|
newHistory[index].content = message
|
||||||
|
setHistory(newHistory)
|
||||||
|
await updateMessageByIndex(historyId, index, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user