useMessageEdit.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { useCallback, useState, useRef } from 'react';
  2. import { Toast, Modal } from '@douyinfe/semi-ui';
  3. import { useTranslation } from 'react-i18next';
  4. import { getTextContent, buildApiPayload, createLoadingAssistantMessage } from '../helpers';
  5. import { MESSAGE_ROLES } from '../constants/playground.constants';
  6. export const useMessageEdit = (
  7. setMessage,
  8. inputs,
  9. parameterEnabled,
  10. sendRequest,
  11. saveMessages
  12. ) => {
  13. const { t } = useTranslation();
  14. const [editingMessageId, setEditingMessageId] = useState(null);
  15. const [editValue, setEditValue] = useState('');
  16. const editingMessageRef = useRef(null);
  17. const handleMessageEdit = useCallback((targetMessage) => {
  18. const editableContent = getTextContent(targetMessage);
  19. setEditingMessageId(targetMessage.id);
  20. editingMessageRef.current = targetMessage;
  21. setEditValue(editableContent);
  22. }, []);
  23. const handleEditSave = useCallback(() => {
  24. if (!editingMessageId || !editValue.trim()) return;
  25. setMessage(prevMessages => {
  26. let messageIndex = prevMessages.findIndex(msg => msg === editingMessageRef.current);
  27. if (messageIndex === -1) {
  28. messageIndex = prevMessages.findIndex(msg => msg.id === editingMessageId);
  29. }
  30. const targetMessage = prevMessages[messageIndex];
  31. let newContent;
  32. if (Array.isArray(targetMessage.content)) {
  33. newContent = targetMessage.content.map(item =>
  34. item.type === 'text' ? { ...item, text: editValue.trim() } : item
  35. );
  36. } else {
  37. newContent = editValue.trim();
  38. }
  39. const updatedMessages = prevMessages.map(msg =>
  40. msg.id === editingMessageId ? { ...msg, content: newContent } : msg
  41. );
  42. // 处理用户消息编辑后的重新生成
  43. if (targetMessage.role === MESSAGE_ROLES.USER) {
  44. const hasSubsequentAssistantReply = messageIndex < prevMessages.length - 1 &&
  45. prevMessages[messageIndex + 1].role === MESSAGE_ROLES.ASSISTANT;
  46. if (hasSubsequentAssistantReply) {
  47. Modal.confirm({
  48. title: t('消息已编辑'),
  49. content: t('检测到该消息后有AI回复,是否删除后续回复并重新生成?'),
  50. okText: t('重新生成'),
  51. cancelText: t('仅保存'),
  52. onOk: () => {
  53. const messagesUntilUser = updatedMessages.slice(0, messageIndex + 1);
  54. setMessage(messagesUntilUser);
  55. // 编辑后保存(重新生成的情况),传入更新后的消息列表
  56. setTimeout(() => saveMessages(messagesUntilUser), 0);
  57. setTimeout(() => {
  58. const payload = buildApiPayload(messagesUntilUser, null, inputs, parameterEnabled);
  59. setMessage(prevMsg => [...prevMsg, createLoadingAssistantMessage()]);
  60. sendRequest(payload, inputs.stream);
  61. }, 100);
  62. },
  63. onCancel: () => {
  64. setMessage(updatedMessages);
  65. // 编辑后保存(仅保存的情况),传入更新后的消息列表
  66. setTimeout(() => saveMessages(updatedMessages), 0);
  67. }
  68. });
  69. return prevMessages;
  70. }
  71. }
  72. // 编辑后保存(普通情况),传入更新后的消息列表
  73. setTimeout(() => saveMessages(updatedMessages), 0);
  74. return updatedMessages;
  75. });
  76. setEditingMessageId(null);
  77. editingMessageRef.current = null;
  78. setEditValue('');
  79. Toast.success({ content: t('消息已更新'), duration: 2 });
  80. }, [editingMessageId, editValue, t, inputs, parameterEnabled, sendRequest, setMessage, saveMessages]);
  81. const handleEditCancel = useCallback(() => {
  82. setEditingMessageId(null);
  83. editingMessageRef.current = null;
  84. setEditValue('');
  85. }, []);
  86. return {
  87. editingMessageId,
  88. editValue,
  89. setEditValue,
  90. handleMessageEdit,
  91. handleEditSave,
  92. handleEditCancel
  93. };
  94. };