Skip to content

Commit 73d3128

Browse files
authored
feat: Regenerate chat message infiniflow#2088 (infiniflow#2166)
### What problem does this PR solve? feat: Regenerate chat message infiniflow#2088 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
1 parent 7c77caa commit 73d3128

File tree

9 files changed

+157
-28
lines changed

9 files changed

+157
-28
lines changed

web/src/components/message-item/group-button.tsx

+23-5
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import {
88
SoundOutlined,
99
SyncOutlined,
1010
} from '@ant-design/icons';
11-
import { Radio } from 'antd';
11+
import { Radio, Tooltip } from 'antd';
1212
import { useCallback } from 'react';
13+
import { useTranslation } from 'react-i18next';
1314
import SvgIcon from '../svg-icon';
1415
import FeedbackModal from './feedback-modal';
1516
import { useRemoveMessage, useSendFeedback } from './hooks';
@@ -33,6 +34,7 @@ export const AssistantGroupButton = ({
3334
hideModal: hidePromptModal,
3435
showModal: showPromptModal,
3536
} = useSetModalState();
37+
const { t } = useTranslation();
3638

3739
const handleLike = useCallback(() => {
3840
onFeedbackOk({ thumbup: true });
@@ -45,7 +47,9 @@ export const AssistantGroupButton = ({
4547
<CopyToClipboard text={content}></CopyToClipboard>
4648
</Radio.Button>
4749
<Radio.Button value="b">
48-
<SoundOutlined />
50+
<Tooltip title={t('chat.read')}>
51+
<SoundOutlined />
52+
</Tooltip>
4953
</Radio.Button>
5054
<Radio.Button value="c" onClick={handleLike}>
5155
<LikeOutlined />
@@ -81,27 +85,41 @@ export const AssistantGroupButton = ({
8185
interface UserGroupButtonProps extends IRemoveMessageById {
8286
messageId: string;
8387
content: string;
88+
regenerateMessage(): void;
89+
sendLoading: boolean;
8490
}
8591

8692
export const UserGroupButton = ({
8793
content,
8894
messageId,
95+
sendLoading,
8996
removeMessageById,
97+
regenerateMessage,
9098
}: UserGroupButtonProps) => {
9199
const { onRemoveMessage, loading } = useRemoveMessage(
92100
messageId,
93101
removeMessageById,
94102
);
103+
const { t } = useTranslation();
104+
95105
return (
96106
<Radio.Group size="small">
97107
<Radio.Button value="a">
98108
<CopyToClipboard text={content}></CopyToClipboard>
99109
</Radio.Button>
100-
<Radio.Button value="b">
101-
<SyncOutlined />
110+
<Radio.Button
111+
value="b"
112+
onClick={regenerateMessage}
113+
disabled={sendLoading}
114+
>
115+
<Tooltip title={t('chat.regenerate')}>
116+
<SyncOutlined spin={sendLoading} />
117+
</Tooltip>
102118
</Radio.Button>
103119
<Radio.Button value="c" onClick={onRemoveMessage} disabled={loading}>
104-
<DeleteOutlined spin={loading} />
120+
<Tooltip title={t('common.delete')}>
121+
<DeleteOutlined spin={loading} />
122+
</Tooltip>
105123
</Radio.Button>
106124
</Radio.Group>
107125
);

web/src/components/message-item/index.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
useFetchDocumentInfosByIds,
1212
useFetchDocumentThumbnailsByIds,
1313
} from '@/hooks/document-hooks';
14-
import { IRemoveMessageById } from '@/hooks/logic-hooks';
14+
import { IRegenerateMessage, IRemoveMessageById } from '@/hooks/logic-hooks';
1515
import { IMessage } from '@/pages/chat/interface';
1616
import MarkdownContent from '@/pages/chat/markdown-content';
1717
import { getExtension, isImage } from '@/utils/document-util';
@@ -24,10 +24,11 @@ import styles from './index.less';
2424

2525
const { Text } = Typography;
2626

27-
interface IProps extends IRemoveMessageById {
27+
interface IProps extends IRemoveMessageById, IRegenerateMessage {
2828
item: IMessage;
2929
reference: IReference;
3030
loading?: boolean;
31+
sendLoading?: boolean;
3132
nickname?: string;
3233
avatar?: string;
3334
clickDocumentButton?: (documentId: string, chunk: IChunk) => void;
@@ -39,9 +40,11 @@ const MessageItem = ({
3940
reference,
4041
loading = false,
4142
avatar = '',
43+
sendLoading = false,
4244
clickDocumentButton,
4345
index,
4446
removeMessageById,
47+
regenerateMessage,
4548
}: IProps) => {
4649
const isAssistant = item.role === MessageType.Assistant;
4750
const isUser = item.role === MessageType.User;
@@ -73,6 +76,10 @@ const MessageItem = ({
7376
[showModal],
7477
);
7578

79+
const handleRegenerateMessage = useCallback(() => {
80+
regenerateMessage(item);
81+
}, [regenerateMessage, item]);
82+
7683
useEffect(() => {
7784
const ids = item?.doc_ids ?? [];
7885
if (ids.length) {
@@ -128,6 +135,8 @@ const MessageItem = ({
128135
content={item.content}
129136
messageId={item.id}
130137
removeMessageById={removeMessageById}
138+
regenerateMessage={handleRegenerateMessage}
139+
sendLoading={sendLoading}
131140
></UserGroupButton>
132141
)}
133142

web/src/hooks/logic-hooks.ts

+73-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Authorization } from '@/constants/authorization';
22
import { LanguageTranslationMap } from '@/constants/common';
33
import { Pagination } from '@/interfaces/common';
44
import { ResponseType } from '@/interfaces/database/base';
5-
import { IAnswer } from '@/interfaces/database/chat';
5+
import { IAnswer, Message } from '@/interfaces/database/chat';
66
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
77
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
88
import { IClientConversation } from '@/pages/chat/interface';
@@ -23,6 +23,7 @@ import {
2323
} from 'react';
2424
import { useTranslation } from 'react-i18next';
2525
import { useDispatch } from 'umi';
26+
import { v4 as uuid } from 'uuid';
2627
import { useSetModalState, useTranslate } from './common-hooks';
2728
import { useSetDocumentParser } from './document-hooks';
2829
import { useSetPaginationParams } from './route-hook';
@@ -336,6 +337,77 @@ export const useRemoveMessageById = (
336337
return { removeMessageById };
337338
};
338339

340+
export const useRemoveMessagesAfterCurrentMessage = (
341+
setCurrentConversation: (
342+
callback: (state: IClientConversation) => IClientConversation,
343+
) => void,
344+
) => {
345+
const removeMessagesAfterCurrentMessage = useCallback(
346+
(messageId: string) => {
347+
setCurrentConversation((pre) => {
348+
const index = pre.message?.findIndex((x) => x.id === messageId);
349+
if (index !== -1) {
350+
let nextMessages = pre.message?.slice(0, index + 2) ?? [];
351+
const latestMessage = nextMessages.at(-1);
352+
nextMessages = latestMessage
353+
? [
354+
...nextMessages.slice(0, -1),
355+
{
356+
...latestMessage,
357+
content: '',
358+
reference: undefined,
359+
prompt: undefined,
360+
},
361+
]
362+
: nextMessages;
363+
return {
364+
...pre,
365+
message: nextMessages,
366+
};
367+
}
368+
return pre;
369+
});
370+
},
371+
[setCurrentConversation],
372+
);
373+
374+
return { removeMessagesAfterCurrentMessage };
375+
};
376+
377+
export interface IRegenerateMessage {
378+
regenerateMessage(message: Message): void;
379+
}
380+
381+
export const useRegenerateMessage = ({
382+
removeMessagesAfterCurrentMessage,
383+
sendMessage,
384+
messages,
385+
}: {
386+
removeMessagesAfterCurrentMessage(messageId: string): void;
387+
sendMessage({ message }: { message: Message; messages?: Message[] }): void;
388+
messages: Message[];
389+
}) => {
390+
const regenerateMessage = useCallback(
391+
async (message: Message) => {
392+
if (message.id) {
393+
removeMessagesAfterCurrentMessage(message.id);
394+
const index = messages.findIndex((x) => x.id === message.id);
395+
let nextMessages;
396+
if (index !== -1) {
397+
nextMessages = messages.slice(0, index);
398+
}
399+
sendMessage({
400+
message: { ...message, id: uuid() },
401+
messages: nextMessages,
402+
});
403+
}
404+
},
405+
[removeMessagesAfterCurrentMessage, sendMessage, messages],
406+
);
407+
408+
return { regenerateMessage };
409+
};
410+
339411
// #endregion
340412

341413
/**

web/src/locales/en.ts

+2
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ The above is the content you need to summarize.`,
425425
parsing: 'Parsing',
426426
uploading: 'Uploading',
427427
uploadFailed: 'Upload failed',
428+
regenerate: 'Regenerate',
429+
read: 'Read content',
428430
},
429431
setting: {
430432
profile: 'Profile',

web/src/locales/zh-traditional.ts

+2
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ export default {
395395
parsing: '解析中',
396396
uploading: '上傳中',
397397
uploadFailed: '上傳失敗',
398+
regenerate: '重新生成',
399+
read: '朗讀內容',
398400
},
399401
setting: {
400402
profile: '概述',

web/src/locales/zh.ts

+2
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ export default {
412412
parsing: '解析中',
413413
uploading: '上传中',
414414
uploadFailed: '上传失败',
415+
regenerate: '重新生成',
416+
read: '朗读内容',
415417
},
416418
setting: {
417419
profile: '概要',

web/src/pages/chat/chat-container/index.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,20 @@ const ChatContainer = () => {
2828
conversationId,
2929
loading,
3030
removeMessageById,
31+
removeMessagesAfterCurrentMessage,
3132
} = useFetchConversationOnMount();
3233
const {
3334
handleInputChange,
3435
handlePressEnter,
3536
value,
3637
loading: sendLoading,
38+
regenerateMessage,
3739
} = useSendMessage(
3840
conversation,
3941
addNewestConversation,
4042
removeLatestMessage,
4143
addNewestAnswer,
44+
removeMessagesAfterCurrentMessage,
4245
);
4346
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
4447
useClickDrawer();
@@ -71,6 +74,8 @@ const ChatContainer = () => {
7174
clickDocumentButton={clickDocumentButton}
7275
index={i}
7376
removeMessageById={removeMessageById}
77+
regenerateMessage={regenerateMessage}
78+
sendLoading={sendLoading}
7479
></MessageItem>
7580
);
7681
})}

0 commit comments

Comments
 (0)