| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- import { useCallback } from 'react';
- import { Toast, Modal } from '@douyinfe/semi-ui';
- import { useTranslation } from 'react-i18next';
- import { getTextContent } from '../helpers';
- import { ERROR_MESSAGES } from '../constants/playground.constants';
- export const useMessageActions = (message, setMessage, onMessageSend, saveMessages) => {
- const { t } = useTranslation();
- // 复制消息
- const handleMessageCopy = useCallback((targetMessage) => {
- const textToCopy = getTextContent(targetMessage);
- if (!textToCopy) {
- Toast.warning({
- content: t(ERROR_MESSAGES.NO_TEXT_CONTENT),
- duration: 2,
- });
- return;
- }
- const copyToClipboard = async (text) => {
- if (navigator.clipboard?.writeText) {
- try {
- await navigator.clipboard.writeText(text);
- Toast.success({
- content: t('消息已复制到剪贴板'),
- duration: 2,
- });
- } catch (err) {
- console.error('Clipboard API 复制失败:', err);
- fallbackCopy(text);
- }
- } else {
- fallbackCopy(text);
- }
- };
- const fallbackCopy = (text) => {
- try {
- const textArea = document.createElement('textarea');
- textArea.value = text;
- textArea.style.cssText = `
- position: fixed;
- top: -9999px;
- left: -9999px;
- opacity: 0;
- pointer-events: none;
- z-index: -1;
- `;
- textArea.setAttribute('readonly', '');
- document.body.appendChild(textArea);
- textArea.select();
- textArea.setSelectionRange(0, text.length);
- const successful = document.execCommand('copy');
- document.body.removeChild(textArea);
- if (successful) {
- Toast.success({
- content: t('消息已复制到剪贴板'),
- duration: 2,
- });
- } else {
- throw new Error('execCommand copy failed');
- }
- } catch (err) {
- console.error('回退复制方案也失败:', err);
- let errorMessage = t(ERROR_MESSAGES.COPY_FAILED);
- if (window.location.protocol === 'http:' && window.location.hostname !== 'localhost') {
- errorMessage = t(ERROR_MESSAGES.COPY_HTTPS_REQUIRED);
- } else if (!navigator.clipboard && !document.execCommand) {
- errorMessage = t(ERROR_MESSAGES.BROWSER_NOT_SUPPORTED);
- }
- Toast.error({
- content: errorMessage,
- duration: 4,
- });
- }
- };
- copyToClipboard(textToCopy);
- }, [t]);
- // 重新生成消息
- const handleMessageReset = useCallback((targetMessage) => {
- setMessage(prevMessages => {
- // 使用引用查找索引,防止重复 id 造成误匹配
- let messageIndex = prevMessages.findIndex(msg => msg === targetMessage);
- // 回退到 id 匹配(兼容不同引用场景)
- if (messageIndex === -1) {
- messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id);
- }
- if (messageIndex === -1) return prevMessages;
- if (targetMessage.role === 'user') {
- const newMessages = prevMessages.slice(0, messageIndex);
- const contentToSend = getTextContent(targetMessage);
- setTimeout(() => {
- onMessageSend(contentToSend);
- }, 100);
- return newMessages;
- } else if (targetMessage.role === 'assistant' || targetMessage.role === 'system') {
- let userMessageIndex = messageIndex - 1;
- while (userMessageIndex >= 0 && prevMessages[userMessageIndex].role !== 'user') {
- userMessageIndex--;
- }
- if (userMessageIndex >= 0) {
- const userMessage = prevMessages[userMessageIndex];
- const newMessages = prevMessages.slice(0, userMessageIndex);
- const contentToSend = getTextContent(userMessage);
- setTimeout(() => {
- onMessageSend(contentToSend);
- }, 100);
- return newMessages;
- }
- }
- return prevMessages;
- });
- }, [setMessage, onMessageSend]);
- // 删除消息
- const handleMessageDelete = useCallback((targetMessage) => {
- Modal.confirm({
- title: t('确认删除'),
- content: t('确定要删除这条消息吗?'),
- okText: t('确定'),
- cancelText: t('取消'),
- okButtonProps: {
- type: 'danger',
- },
- onOk: () => {
- setMessage(prevMessages => {
- // 使用引用查找索引,防止重复 id 造成误匹配
- let messageIndex = prevMessages.findIndex(msg => msg === targetMessage);
- // 回退到 id 匹配(兼容不同引用场景)
- if (messageIndex === -1) {
- messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id);
- }
- if (messageIndex === -1) return prevMessages;
- let updatedMessages;
- if (targetMessage.role === 'user' && messageIndex < prevMessages.length - 1) {
- const nextMessage = prevMessages[messageIndex + 1];
- if (nextMessage.role === 'assistant') {
- Toast.success({
- content: t('已删除消息及其回复'),
- duration: 2,
- });
- updatedMessages = prevMessages.filter((_, index) =>
- index !== messageIndex && index !== messageIndex + 1
- );
- } else {
- Toast.success({
- content: t('消息已删除'),
- duration: 2,
- });
- updatedMessages = prevMessages.filter(msg => msg.id !== targetMessage.id);
- }
- } else {
- Toast.success({
- content: t('消息已删除'),
- duration: 2,
- });
- updatedMessages = prevMessages.filter(msg => msg.id !== targetMessage.id);
- }
- // 删除消息后保存,传入更新后的消息列表
- setTimeout(() => saveMessages(updatedMessages), 0);
- return updatedMessages;
- });
- },
- });
- }, [setMessage, t, saveMessages]);
- // 切换角色
- const handleRoleToggle = useCallback((targetMessage) => {
- if (!(targetMessage.role === 'assistant' || targetMessage.role === 'system')) {
- return;
- }
- const newRole = targetMessage.role === 'assistant' ? 'system' : 'assistant';
- setMessage(prevMessages => {
- const updatedMessages = prevMessages.map(msg => {
- if (msg.id === targetMessage.id &&
- (msg.role === 'assistant' || msg.role === 'system')) {
- return { ...msg, role: newRole };
- }
- return msg;
- });
- // 切换角色后保存,传入更新后的消息列表
- setTimeout(() => saveMessages(updatedMessages), 0);
- return updatedMessages;
- });
- Toast.success({
- content: t(`已切换为${newRole === 'system' ? 'System' : 'Assistant'}角色`),
- duration: 2,
- });
- }, [setMessage, t, saveMessages]);
- return {
- handleMessageCopy,
- handleMessageReset,
- handleMessageDelete,
- handleRoleToggle,
- };
- };
|