| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import { useCallback, useState, useRef } from 'react'; |
| | import { Toast, Modal } from '@douyinfe/semi-ui'; |
| | import { useTranslation } from 'react-i18next'; |
| | import { |
| | getTextContent, |
| | buildApiPayload, |
| | createLoadingAssistantMessage, |
| | } from '../../helpers'; |
| | import { MESSAGE_ROLES } from '../../constants/playground.constants'; |
| |
|
| | export const useMessageEdit = ( |
| | setMessage, |
| | inputs, |
| | parameterEnabled, |
| | sendRequest, |
| | saveMessages, |
| | ) => { |
| | const { t } = useTranslation(); |
| | const [editingMessageId, setEditingMessageId] = useState(null); |
| | const [editValue, setEditValue] = useState(''); |
| | const editingMessageRef = useRef(null); |
| |
|
| | const handleMessageEdit = useCallback((targetMessage) => { |
| | const editableContent = getTextContent(targetMessage); |
| | setEditingMessageId(targetMessage.id); |
| | editingMessageRef.current = targetMessage; |
| | setEditValue(editableContent); |
| | }, []); |
| |
|
| | const handleEditSave = useCallback(() => { |
| | if (!editingMessageId || !editValue.trim()) return; |
| |
|
| | setMessage((prevMessages) => { |
| | let messageIndex = prevMessages.findIndex( |
| | (msg) => msg === editingMessageRef.current, |
| | ); |
| |
|
| | if (messageIndex === -1) { |
| | messageIndex = prevMessages.findIndex( |
| | (msg) => msg.id === editingMessageId, |
| | ); |
| | } |
| |
|
| | const targetMessage = prevMessages[messageIndex]; |
| | let newContent; |
| |
|
| | if (Array.isArray(targetMessage.content)) { |
| | newContent = targetMessage.content.map((item) => |
| | item.type === 'text' ? { ...item, text: editValue.trim() } : item, |
| | ); |
| | } else { |
| | newContent = editValue.trim(); |
| | } |
| |
|
| | const updatedMessages = prevMessages.map((msg) => |
| | msg.id === editingMessageId ? { ...msg, content: newContent } : msg, |
| | ); |
| |
|
| | |
| | if (targetMessage.role === MESSAGE_ROLES.USER) { |
| | const hasSubsequentAssistantReply = |
| | messageIndex < prevMessages.length - 1 && |
| | prevMessages[messageIndex + 1].role === MESSAGE_ROLES.ASSISTANT; |
| |
|
| | if (hasSubsequentAssistantReply) { |
| | Modal.confirm({ |
| | title: t('消息已编辑'), |
| | content: t('检测到该消息后有AI回复,是否删除后续回复并重新生成?'), |
| | okText: t('重新生成'), |
| | cancelText: t('仅保存'), |
| | onOk: () => { |
| | const messagesUntilUser = updatedMessages.slice( |
| | 0, |
| | messageIndex + 1, |
| | ); |
| | setMessage(messagesUntilUser); |
| | |
| | setTimeout(() => saveMessages(messagesUntilUser), 0); |
| |
|
| | setTimeout(() => { |
| | const payload = buildApiPayload( |
| | messagesUntilUser, |
| | null, |
| | inputs, |
| | parameterEnabled, |
| | ); |
| | setMessage((prevMsg) => [ |
| | ...prevMsg, |
| | createLoadingAssistantMessage(), |
| | ]); |
| | sendRequest(payload, inputs.stream); |
| | }, 100); |
| | }, |
| | onCancel: () => { |
| | setMessage(updatedMessages); |
| | |
| | setTimeout(() => saveMessages(updatedMessages), 0); |
| | }, |
| | }); |
| | return prevMessages; |
| | } |
| | } |
| |
|
| | |
| | setTimeout(() => saveMessages(updatedMessages), 0); |
| | return updatedMessages; |
| | }); |
| |
|
| | setEditingMessageId(null); |
| | editingMessageRef.current = null; |
| | setEditValue(''); |
| | Toast.success({ content: t('消息已更新'), duration: 2 }); |
| | }, [ |
| | editingMessageId, |
| | editValue, |
| | t, |
| | inputs, |
| | parameterEnabled, |
| | sendRequest, |
| | setMessage, |
| | saveMessages, |
| | ]); |
| |
|
| | const handleEditCancel = useCallback(() => { |
| | setEditingMessageId(null); |
| | editingMessageRef.current = null; |
| | setEditValue(''); |
| | }, []); |
| |
|
| | return { |
| | editingMessageId, |
| | editValue, |
| | setEditValue, |
| | handleMessageEdit, |
| | handleEditSave, |
| | handleEditCancel, |
| | }; |
| | }; |
| |
|