balibabu
commited on
Commit
·
8a4bb0c
1
Parent(s):
8f5dc1b
feat: Select derived messages from backend #2088 (#2176)
Browse files### What problem does this PR solve?
feat: Select derived messages from backend #2088
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/components/message-item/group-button.tsx +12 -10
- web/src/components/message-item/index.tsx +4 -2
- web/src/hooks/chat-hooks.ts +8 -21
- web/src/hooks/flow-hooks.ts +8 -0
- web/src/hooks/logic-hooks.ts +112 -4
- web/src/pages/chat/chat-container/index.tsx +22 -22
- web/src/pages/chat/hooks.ts +193 -10
- web/src/pages/chat/share/large.tsx +16 -21
- web/src/pages/chat/shared-hooks.ts +41 -112
- web/src/pages/chat/utils.ts +1 -1
- web/src/pages/flow/chat/box.tsx +12 -17
- web/src/pages/flow/chat/hooks.ts +118 -0
- web/src/utils/chat.ts +9 -0
web/src/components/message-item/group-button.tsx
CHANGED
@@ -91,7 +91,7 @@ export const AssistantGroupButton = ({
|
|
91 |
interface UserGroupButtonProps extends Partial<IRemoveMessageById> {
|
92 |
messageId: string;
|
93 |
content: string;
|
94 |
-
regenerateMessage()
|
95 |
sendLoading: boolean;
|
96 |
}
|
97 |
|
@@ -113,15 +113,17 @@ export const UserGroupButton = ({
|
|
113 |
<Radio.Button value="a">
|
114 |
<CopyToClipboard text={content}></CopyToClipboard>
|
115 |
</Radio.Button>
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
<
|
123 |
-
|
124 |
-
|
|
|
|
|
125 |
{removeMessageById && (
|
126 |
<Radio.Button value="c" onClick={onRemoveMessage} disabled={loading}>
|
127 |
<Tooltip title={t('common.delete')}>
|
|
|
91 |
interface UserGroupButtonProps extends Partial<IRemoveMessageById> {
|
92 |
messageId: string;
|
93 |
content: string;
|
94 |
+
regenerateMessage?: () => void;
|
95 |
sendLoading: boolean;
|
96 |
}
|
97 |
|
|
|
113 |
<Radio.Button value="a">
|
114 |
<CopyToClipboard text={content}></CopyToClipboard>
|
115 |
</Radio.Button>
|
116 |
+
{regenerateMessage && (
|
117 |
+
<Radio.Button
|
118 |
+
value="b"
|
119 |
+
onClick={regenerateMessage}
|
120 |
+
disabled={sendLoading}
|
121 |
+
>
|
122 |
+
<Tooltip title={t('chat.regenerate')}>
|
123 |
+
<SyncOutlined spin={sendLoading} />
|
124 |
+
</Tooltip>
|
125 |
+
</Radio.Button>
|
126 |
+
)}
|
127 |
{removeMessageById && (
|
128 |
<Radio.Button value="c" onClick={onRemoveMessage} disabled={loading}>
|
129 |
<Tooltip title={t('common.delete')}>
|
web/src/components/message-item/index.tsx
CHANGED
@@ -79,7 +79,7 @@ const MessageItem = ({
|
|
79 |
);
|
80 |
|
81 |
const handleRegenerateMessage = useCallback(() => {
|
82 |
-
regenerateMessage(item);
|
83 |
}, [regenerateMessage, item]);
|
84 |
|
85 |
useEffect(() => {
|
@@ -138,7 +138,9 @@ const MessageItem = ({
|
|
138 |
content={item.content}
|
139 |
messageId={item.id}
|
140 |
removeMessageById={removeMessageById}
|
141 |
-
regenerateMessage={
|
|
|
|
|
142 |
sendLoading={sendLoading}
|
143 |
></UserGroupButton>
|
144 |
)}
|
|
|
79 |
);
|
80 |
|
81 |
const handleRegenerateMessage = useCallback(() => {
|
82 |
+
regenerateMessage?.(item);
|
83 |
}, [regenerateMessage, item]);
|
84 |
|
85 |
useEffect(() => {
|
|
|
138 |
content={item.content}
|
139 |
messageId={item.id}
|
140 |
removeMessageById={removeMessageById}
|
141 |
+
regenerateMessage={
|
142 |
+
regenerateMessage && handleRegenerateMessage
|
143 |
+
}
|
144 |
sendLoading={sendLoading}
|
145 |
></UserGroupButton>
|
146 |
)}
|
web/src/hooks/chat-hooks.ts
CHANGED
@@ -4,13 +4,12 @@ import {
|
|
4 |
IDialog,
|
5 |
IStats,
|
6 |
IToken,
|
7 |
-
Message,
|
8 |
} from '@/interfaces/database/chat';
|
9 |
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
|
10 |
import i18n from '@/locales/config';
|
11 |
-
import { IClientConversation
|
12 |
import chatService from '@/services/chat-service';
|
13 |
-
import {
|
14 |
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
15 |
import { message } from 'antd';
|
16 |
import dayjs, { Dayjs } from 'dayjs';
|
@@ -18,15 +17,6 @@ import { set } from 'lodash';
|
|
18 |
import { useCallback, useMemo, useState } from 'react';
|
19 |
import { useSearchParams } from 'umi';
|
20 |
|
21 |
-
const buildMessageListWithUuid = (messages?: Message[]) => {
|
22 |
-
return (
|
23 |
-
messages?.map((x: Message | IMessage) => ({
|
24 |
-
...x,
|
25 |
-
id: buildMessageUuid(x),
|
26 |
-
})) ?? []
|
27 |
-
);
|
28 |
-
};
|
29 |
-
|
30 |
//#region logic
|
31 |
|
32 |
export const useClickDialogCard = () => {
|
@@ -465,14 +455,11 @@ export const useCreateNextSharedConversation = () => {
|
|
465 |
return { data, loading, createSharedConversation: mutateAsync };
|
466 |
};
|
467 |
|
468 |
-
export const useFetchNextSharedConversation = () => {
|
469 |
-
const {
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
} = useMutation({
|
474 |
-
mutationKey: ['fetchSharedConversation'],
|
475 |
-
mutationFn: async (conversationId: string) => {
|
476 |
const { data } = await chatService.getExternalConversation(
|
477 |
null,
|
478 |
conversationId,
|
@@ -486,7 +473,7 @@ export const useFetchNextSharedConversation = () => {
|
|
486 |
},
|
487 |
});
|
488 |
|
489 |
-
return { data, loading
|
490 |
};
|
491 |
|
492 |
//#endregion
|
|
|
4 |
IDialog,
|
5 |
IStats,
|
6 |
IToken,
|
|
|
7 |
} from '@/interfaces/database/chat';
|
8 |
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
|
9 |
import i18n from '@/locales/config';
|
10 |
+
import { IClientConversation } from '@/pages/chat/interface';
|
11 |
import chatService from '@/services/chat-service';
|
12 |
+
import { buildMessageListWithUuid, isConversationIdExist } from '@/utils/chat';
|
13 |
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
14 |
import { message } from 'antd';
|
15 |
import dayjs, { Dayjs } from 'dayjs';
|
|
|
17 |
import { useCallback, useMemo, useState } from 'react';
|
18 |
import { useSearchParams } from 'umi';
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
//#region logic
|
21 |
|
22 |
export const useClickDialogCard = () => {
|
|
|
455 |
return { data, loading, createSharedConversation: mutateAsync };
|
456 |
};
|
457 |
|
458 |
+
export const useFetchNextSharedConversation = (conversationId: string) => {
|
459 |
+
const { data, isPending: loading } = useQuery({
|
460 |
+
queryKey: ['fetchSharedConversation'],
|
461 |
+
enabled: !!conversationId,
|
462 |
+
queryFn: async () => {
|
|
|
|
|
|
|
463 |
const { data } = await chatService.getExternalConversation(
|
464 |
null,
|
465 |
conversationId,
|
|
|
473 |
},
|
474 |
});
|
475 |
|
476 |
+
return { data, loading };
|
477 |
};
|
478 |
|
479 |
//#endregion
|
web/src/hooks/flow-hooks.ts
CHANGED
@@ -2,8 +2,11 @@ import { ResponseType } from '@/interfaces/database/base';
|
|
2 |
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
3 |
import i18n from '@/locales/config';
|
4 |
import flowService from '@/services/flow-service';
|
|
|
5 |
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
6 |
import { message } from 'antd';
|
|
|
|
|
7 |
import { useParams } from 'umi';
|
8 |
import { v4 as uuid } from 'uuid';
|
9 |
|
@@ -101,6 +104,11 @@ export const useFetchFlow = (): {
|
|
101 |
queryFn: async () => {
|
102 |
const { data } = await flowService.getCanvas({}, id);
|
103 |
|
|
|
|
|
|
|
|
|
|
|
104 |
return data?.data ?? {};
|
105 |
},
|
106 |
});
|
|
|
2 |
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
3 |
import i18n from '@/locales/config';
|
4 |
import flowService from '@/services/flow-service';
|
5 |
+
import { buildMessageListWithUuid } from '@/utils/chat';
|
6 |
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
7 |
import { message } from 'antd';
|
8 |
+
import { set } from 'lodash';
|
9 |
+
import get from 'lodash/get';
|
10 |
import { useParams } from 'umi';
|
11 |
import { v4 as uuid } from 'uuid';
|
12 |
|
|
|
104 |
queryFn: async () => {
|
105 |
const { data } = await flowService.getCanvas({}, id);
|
106 |
|
107 |
+
const messageList = buildMessageListWithUuid(
|
108 |
+
get(data, 'data.dsl.messages', []),
|
109 |
+
);
|
110 |
+
set(data, 'data.dsl.messages', messageList);
|
111 |
+
|
112 |
return data?.data ?? {};
|
113 |
},
|
114 |
});
|
web/src/hooks/logic-hooks.ts
CHANGED
@@ -1,14 +1,15 @@
|
|
1 |
import { Authorization } from '@/constants/authorization';
|
|
|
2 |
import { LanguageTranslationMap } from '@/constants/common';
|
3 |
import { Pagination } from '@/interfaces/common';
|
4 |
import { ResponseType } from '@/interfaces/database/base';
|
5 |
import { IAnswer, Message } from '@/interfaces/database/chat';
|
6 |
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
7 |
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
8 |
-
import { IClientConversation } from '@/pages/chat/interface';
|
9 |
import api from '@/utils/api';
|
10 |
import { getAuthorization } from '@/utils/authorization-util';
|
11 |
-
import { getMessagePureId } from '@/utils/chat';
|
12 |
import { PaginationProps } from 'antd';
|
13 |
import { FormInstance } from 'antd/lib';
|
14 |
import axios from 'axios';
|
@@ -309,6 +310,108 @@ export const useHandleMessageInputChange = () => {
|
|
309 |
};
|
310 |
};
|
311 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
export interface IRemoveMessageById {
|
313 |
removeMessageById(messageId: string): void;
|
314 |
}
|
@@ -375,7 +478,7 @@ export const useRemoveMessagesAfterCurrentMessage = (
|
|
375 |
};
|
376 |
|
377 |
export interface IRegenerateMessage {
|
378 |
-
regenerateMessage(message: Message)
|
379 |
}
|
380 |
|
381 |
export const useRegenerateMessage = ({
|
@@ -384,7 +487,12 @@ export const useRegenerateMessage = ({
|
|
384 |
messages,
|
385 |
}: {
|
386 |
removeMessagesAfterCurrentMessage(messageId: string): void;
|
387 |
-
sendMessage({
|
|
|
|
|
|
|
|
|
|
|
388 |
messages: Message[];
|
389 |
}) => {
|
390 |
const regenerateMessage = useCallback(
|
|
|
1 |
import { Authorization } from '@/constants/authorization';
|
2 |
+
import { MessageType } from '@/constants/chat';
|
3 |
import { LanguageTranslationMap } from '@/constants/common';
|
4 |
import { Pagination } from '@/interfaces/common';
|
5 |
import { ResponseType } from '@/interfaces/database/base';
|
6 |
import { IAnswer, Message } from '@/interfaces/database/chat';
|
7 |
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
8 |
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
9 |
+
import { IClientConversation, IMessage } from '@/pages/chat/interface';
|
10 |
import api from '@/utils/api';
|
11 |
import { getAuthorization } from '@/utils/authorization-util';
|
12 |
+
import { buildMessageUuid, getMessagePureId } from '@/utils/chat';
|
13 |
import { PaginationProps } from 'antd';
|
14 |
import { FormInstance } from 'antd/lib';
|
15 |
import axios from 'axios';
|
|
|
310 |
};
|
311 |
};
|
312 |
|
313 |
+
export const useSelectDerivedMessages = () => {
|
314 |
+
const [derivedMessages, setDerivedMessages] = useState<IMessage[]>([]);
|
315 |
+
|
316 |
+
const ref = useScrollToBottom(derivedMessages);
|
317 |
+
|
318 |
+
const addNewestQuestion = useCallback(
|
319 |
+
(message: Message, answer: string = '') => {
|
320 |
+
setDerivedMessages((pre) => {
|
321 |
+
return [
|
322 |
+
...pre,
|
323 |
+
{
|
324 |
+
...message,
|
325 |
+
id: buildMessageUuid(message),
|
326 |
+
},
|
327 |
+
{
|
328 |
+
role: MessageType.Assistant,
|
329 |
+
content: answer,
|
330 |
+
id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
|
331 |
+
},
|
332 |
+
];
|
333 |
+
});
|
334 |
+
},
|
335 |
+
[],
|
336 |
+
);
|
337 |
+
|
338 |
+
// Add the streaming message to the last item in the message list
|
339 |
+
const addNewestAnswer = useCallback((answer: IAnswer) => {
|
340 |
+
setDerivedMessages((pre) => {
|
341 |
+
return [
|
342 |
+
...(pre?.slice(0, -1) ?? []),
|
343 |
+
{
|
344 |
+
role: MessageType.Assistant,
|
345 |
+
content: answer.answer,
|
346 |
+
reference: answer.reference,
|
347 |
+
id: buildMessageUuid({
|
348 |
+
id: answer.id,
|
349 |
+
role: MessageType.Assistant,
|
350 |
+
}),
|
351 |
+
prompt: answer.prompt,
|
352 |
+
},
|
353 |
+
];
|
354 |
+
});
|
355 |
+
}, []);
|
356 |
+
|
357 |
+
const removeLatestMessage = useCallback(() => {
|
358 |
+
setDerivedMessages((pre) => {
|
359 |
+
const nextMessages = pre?.slice(0, -2) ?? [];
|
360 |
+
return nextMessages;
|
361 |
+
});
|
362 |
+
}, []);
|
363 |
+
|
364 |
+
const removeMessageById = useCallback(
|
365 |
+
(messageId: string) => {
|
366 |
+
setDerivedMessages((pre) => {
|
367 |
+
const nextMessages =
|
368 |
+
pre?.filter(
|
369 |
+
(x) => getMessagePureId(x.id) !== getMessagePureId(messageId),
|
370 |
+
) ?? [];
|
371 |
+
return nextMessages;
|
372 |
+
});
|
373 |
+
},
|
374 |
+
[setDerivedMessages],
|
375 |
+
);
|
376 |
+
|
377 |
+
const removeMessagesAfterCurrentMessage = useCallback(
|
378 |
+
(messageId: string) => {
|
379 |
+
setDerivedMessages((pre) => {
|
380 |
+
const index = pre.findIndex((x) => x.id === messageId);
|
381 |
+
if (index !== -1) {
|
382 |
+
let nextMessages = pre.slice(0, index + 2) ?? [];
|
383 |
+
const latestMessage = nextMessages.at(-1);
|
384 |
+
nextMessages = latestMessage
|
385 |
+
? [
|
386 |
+
...nextMessages.slice(0, -1),
|
387 |
+
{
|
388 |
+
...latestMessage,
|
389 |
+
content: '',
|
390 |
+
reference: undefined,
|
391 |
+
prompt: undefined,
|
392 |
+
},
|
393 |
+
]
|
394 |
+
: nextMessages;
|
395 |
+
return nextMessages;
|
396 |
+
}
|
397 |
+
return pre;
|
398 |
+
});
|
399 |
+
},
|
400 |
+
[setDerivedMessages],
|
401 |
+
);
|
402 |
+
|
403 |
+
return {
|
404 |
+
ref,
|
405 |
+
derivedMessages,
|
406 |
+
setDerivedMessages,
|
407 |
+
addNewestQuestion,
|
408 |
+
addNewestAnswer,
|
409 |
+
removeLatestMessage,
|
410 |
+
removeMessageById,
|
411 |
+
removeMessagesAfterCurrentMessage,
|
412 |
+
};
|
413 |
+
};
|
414 |
+
|
415 |
export interface IRemoveMessageById {
|
416 |
removeMessageById(messageId: string): void;
|
417 |
}
|
|
|
478 |
};
|
479 |
|
480 |
export interface IRegenerateMessage {
|
481 |
+
regenerateMessage?: (message: Message) => void;
|
482 |
}
|
483 |
|
484 |
export const useRegenerateMessage = ({
|
|
|
487 |
messages,
|
488 |
}: {
|
489 |
removeMessagesAfterCurrentMessage(messageId: string): void;
|
490 |
+
sendMessage({
|
491 |
+
message,
|
492 |
+
}: {
|
493 |
+
message: Message;
|
494 |
+
messages?: Message[];
|
495 |
+
}): void | Promise<any>;
|
496 |
messages: Message[];
|
497 |
}) => {
|
498 |
const regenerateMessage = useCallback(
|
web/src/pages/chat/chat-container/index.tsx
CHANGED
@@ -5,44 +5,38 @@ import { Drawer, Flex, Spin } from 'antd';
|
|
5 |
import {
|
6 |
useClickDrawer,
|
7 |
useCreateConversationBeforeUploadDocument,
|
8 |
-
useFetchConversationOnMount,
|
9 |
useGetFileIcon,
|
10 |
useGetSendButtonDisabled,
|
11 |
useSendButtonDisabled,
|
12 |
-
|
13 |
} from '../hooks';
|
14 |
import { buildMessageItemReference } from '../utils';
|
15 |
|
16 |
import MessageInput from '@/components/message-input';
|
|
|
|
|
|
|
|
|
17 |
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
18 |
import { memo } from 'react';
|
19 |
import styles from './index.less';
|
20 |
|
21 |
const ChatContainer = () => {
|
|
|
|
|
|
|
22 |
const {
|
23 |
ref,
|
24 |
-
currentConversation: conversation,
|
25 |
-
addNewestConversation,
|
26 |
-
removeLatestMessage,
|
27 |
-
addNewestAnswer,
|
28 |
-
conversationId,
|
29 |
loading,
|
30 |
-
|
31 |
-
|
32 |
-
} = useFetchConversationOnMount();
|
33 |
-
const {
|
34 |
handleInputChange,
|
35 |
handlePressEnter,
|
36 |
value,
|
37 |
-
loading: sendLoading,
|
38 |
regenerateMessage,
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
removeLatestMessage,
|
43 |
-
addNewestAnswer,
|
44 |
-
removeMessagesAfterCurrentMessage,
|
45 |
-
);
|
46 |
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
47 |
useClickDrawer();
|
48 |
const disabled = useGetSendButtonDisabled();
|
@@ -58,19 +52,25 @@ const ChatContainer = () => {
|
|
58 |
<Flex flex={1} vertical className={styles.messageContainer}>
|
59 |
<div>
|
60 |
<Spin spinning={loading}>
|
61 |
-
{
|
62 |
return (
|
63 |
<MessageItem
|
64 |
loading={
|
65 |
message.role === MessageType.Assistant &&
|
66 |
sendLoading &&
|
67 |
-
|
68 |
}
|
69 |
key={message.id}
|
70 |
item={message}
|
71 |
nickname={userInfo.nickname}
|
72 |
avatar={userInfo.avatar}
|
73 |
-
reference={buildMessageItemReference(
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
clickDocumentButton={clickDocumentButton}
|
75 |
index={i}
|
76 |
removeMessageById={removeMessageById}
|
|
|
5 |
import {
|
6 |
useClickDrawer,
|
7 |
useCreateConversationBeforeUploadDocument,
|
|
|
8 |
useGetFileIcon,
|
9 |
useGetSendButtonDisabled,
|
10 |
useSendButtonDisabled,
|
11 |
+
useSendNextMessage,
|
12 |
} from '../hooks';
|
13 |
import { buildMessageItemReference } from '../utils';
|
14 |
|
15 |
import MessageInput from '@/components/message-input';
|
16 |
+
import {
|
17 |
+
useFetchNextConversation,
|
18 |
+
useGetChatSearchParams,
|
19 |
+
} from '@/hooks/chat-hooks';
|
20 |
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
21 |
import { memo } from 'react';
|
22 |
import styles from './index.less';
|
23 |
|
24 |
const ChatContainer = () => {
|
25 |
+
const { conversationId } = useGetChatSearchParams();
|
26 |
+
const { data: conversation } = useFetchNextConversation();
|
27 |
+
|
28 |
const {
|
29 |
ref,
|
|
|
|
|
|
|
|
|
|
|
30 |
loading,
|
31 |
+
sendLoading,
|
32 |
+
derivedMessages,
|
|
|
|
|
33 |
handleInputChange,
|
34 |
handlePressEnter,
|
35 |
value,
|
|
|
36 |
regenerateMessage,
|
37 |
+
removeMessageById,
|
38 |
+
} = useSendNextMessage();
|
39 |
+
|
|
|
|
|
|
|
|
|
40 |
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
41 |
useClickDrawer();
|
42 |
const disabled = useGetSendButtonDisabled();
|
|
|
52 |
<Flex flex={1} vertical className={styles.messageContainer}>
|
53 |
<div>
|
54 |
<Spin spinning={loading}>
|
55 |
+
{derivedMessages?.map((message, i) => {
|
56 |
return (
|
57 |
<MessageItem
|
58 |
loading={
|
59 |
message.role === MessageType.Assistant &&
|
60 |
sendLoading &&
|
61 |
+
derivedMessages.length - 1 === i
|
62 |
}
|
63 |
key={message.id}
|
64 |
item={message}
|
65 |
nickname={userInfo.nickname}
|
66 |
avatar={userInfo.avatar}
|
67 |
+
reference={buildMessageItemReference(
|
68 |
+
{
|
69 |
+
message: derivedMessages,
|
70 |
+
reference: conversation.reference,
|
71 |
+
},
|
72 |
+
message,
|
73 |
+
)}
|
74 |
clickDocumentButton={clickDocumentButton}
|
75 |
index={i}
|
76 |
removeMessageById={removeMessageById}
|
web/src/pages/chat/hooks.ts
CHANGED
@@ -21,6 +21,8 @@ import {
|
|
21 |
useRegenerateMessage,
|
22 |
useRemoveMessageById,
|
23 |
useRemoveMessagesAfterCurrentMessage,
|
|
|
|
|
24 |
useSendMessageWithSse,
|
25 |
} from '@/hooks/logic-hooks';
|
26 |
import {
|
@@ -40,7 +42,6 @@ import {
|
|
40 |
useCallback,
|
41 |
useEffect,
|
42 |
useMemo,
|
43 |
-
useRef,
|
44 |
useState,
|
45 |
} from 'react';
|
46 |
import { useSearchParams } from 'umi';
|
@@ -362,20 +363,71 @@ export const useSelectCurrentConversation = () => {
|
|
362 |
};
|
363 |
};
|
364 |
|
365 |
-
export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
366 |
-
|
367 |
|
368 |
-
|
369 |
-
|
370 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
}
|
372 |
-
}, [
|
|
|
|
|
|
|
|
|
373 |
|
374 |
useEffect(() => {
|
375 |
-
|
376 |
-
|
|
|
|
|
377 |
|
378 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
379 |
};
|
380 |
|
381 |
export const useFetchConversationOnMount = () => {
|
@@ -544,6 +596,137 @@ export const useSendMessage = (
|
|
544 |
};
|
545 |
};
|
546 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
export const useGetFileIcon = () => {
|
548 |
const getFileIcon = (filename: string) => {
|
549 |
const ext: string = getFileExtension(filename);
|
|
|
21 |
useRegenerateMessage,
|
22 |
useRemoveMessageById,
|
23 |
useRemoveMessagesAfterCurrentMessage,
|
24 |
+
useScrollToBottom,
|
25 |
+
useSelectDerivedMessages,
|
26 |
useSendMessageWithSse,
|
27 |
} from '@/hooks/logic-hooks';
|
28 |
import {
|
|
|
42 |
useCallback,
|
43 |
useEffect,
|
44 |
useMemo,
|
|
|
45 |
useState,
|
46 |
} from 'react';
|
47 |
import { useSearchParams } from 'umi';
|
|
|
363 |
};
|
364 |
};
|
365 |
|
366 |
+
// export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
367 |
+
// const ref = useRef<HTMLDivElement>(null);
|
368 |
|
369 |
+
// const scrollToBottom = useCallback(() => {
|
370 |
+
// if (currentConversation.id) {
|
371 |
+
// ref.current?.scrollIntoView({ behavior: 'instant' });
|
372 |
+
// }
|
373 |
+
// }, [currentConversation]);
|
374 |
+
|
375 |
+
// useEffect(() => {
|
376 |
+
// scrollToBottom();
|
377 |
+
// }, [scrollToBottom]);
|
378 |
+
|
379 |
+
// return ref;
|
380 |
+
// };
|
381 |
+
|
382 |
+
export const useSelectNextMessages = () => {
|
383 |
+
const {
|
384 |
+
ref,
|
385 |
+
setDerivedMessages,
|
386 |
+
derivedMessages,
|
387 |
+
addNewestAnswer,
|
388 |
+
addNewestQuestion,
|
389 |
+
removeLatestMessage,
|
390 |
+
removeMessageById,
|
391 |
+
removeMessagesAfterCurrentMessage,
|
392 |
+
} = useSelectDerivedMessages();
|
393 |
+
const { data: conversation, loading } = useFetchNextConversation();
|
394 |
+
const { data: dialog } = useFetchNextDialog();
|
395 |
+
const { conversationId, dialogId } = useGetChatSearchParams();
|
396 |
+
|
397 |
+
const addPrologue = useCallback(() => {
|
398 |
+
if (dialogId !== '' && conversationId === '') {
|
399 |
+
const prologue = dialog.prompt_config?.prologue;
|
400 |
+
|
401 |
+
const nextMessage = {
|
402 |
+
role: MessageType.Assistant,
|
403 |
+
content: prologue,
|
404 |
+
id: uuid(),
|
405 |
+
} as IMessage;
|
406 |
+
|
407 |
+
setDerivedMessages([nextMessage]);
|
408 |
}
|
409 |
+
}, [conversationId, dialog, dialogId, setDerivedMessages]);
|
410 |
+
|
411 |
+
useEffect(() => {
|
412 |
+
addPrologue();
|
413 |
+
}, [addPrologue]);
|
414 |
|
415 |
useEffect(() => {
|
416 |
+
if (conversationId) {
|
417 |
+
setDerivedMessages(conversation.message);
|
418 |
+
}
|
419 |
+
}, [conversation.message, conversationId, setDerivedMessages]);
|
420 |
|
421 |
+
return {
|
422 |
+
ref,
|
423 |
+
derivedMessages,
|
424 |
+
loading,
|
425 |
+
addNewestAnswer,
|
426 |
+
addNewestQuestion,
|
427 |
+
removeLatestMessage,
|
428 |
+
removeMessageById,
|
429 |
+
removeMessagesAfterCurrentMessage,
|
430 |
+
};
|
431 |
};
|
432 |
|
433 |
export const useFetchConversationOnMount = () => {
|
|
|
596 |
};
|
597 |
};
|
598 |
|
599 |
+
export const useSendNextMessage = () => {
|
600 |
+
const { setConversation } = useSetConversation();
|
601 |
+
const { conversationId } = useGetChatSearchParams();
|
602 |
+
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
603 |
+
const { handleClickConversation } = useClickConversationCard();
|
604 |
+
const { send, answer, done, setDone } = useSendMessageWithSse();
|
605 |
+
const {
|
606 |
+
ref,
|
607 |
+
derivedMessages,
|
608 |
+
loading,
|
609 |
+
addNewestAnswer,
|
610 |
+
addNewestQuestion,
|
611 |
+
removeLatestMessage,
|
612 |
+
removeMessageById,
|
613 |
+
removeMessagesAfterCurrentMessage,
|
614 |
+
} = useSelectNextMessages();
|
615 |
+
|
616 |
+
const sendMessage = useCallback(
|
617 |
+
async ({
|
618 |
+
message,
|
619 |
+
currentConversationId,
|
620 |
+
messages,
|
621 |
+
}: {
|
622 |
+
message: Message;
|
623 |
+
currentConversationId?: string;
|
624 |
+
messages?: Message[];
|
625 |
+
}) => {
|
626 |
+
const res = await send({
|
627 |
+
conversation_id: currentConversationId ?? conversationId,
|
628 |
+
messages: [...(messages ?? derivedMessages ?? []), message],
|
629 |
+
});
|
630 |
+
|
631 |
+
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
632 |
+
// cancel loading
|
633 |
+
setValue(message.content);
|
634 |
+
console.info('removeLatestMessage111');
|
635 |
+
removeLatestMessage();
|
636 |
+
} else {
|
637 |
+
if (currentConversationId) {
|
638 |
+
console.info('111');
|
639 |
+
// new conversation
|
640 |
+
handleClickConversation(currentConversationId);
|
641 |
+
} else {
|
642 |
+
console.info('222');
|
643 |
+
// fetchConversation(conversationId);
|
644 |
+
}
|
645 |
+
}
|
646 |
+
},
|
647 |
+
[
|
648 |
+
derivedMessages,
|
649 |
+
conversationId,
|
650 |
+
handleClickConversation,
|
651 |
+
removeLatestMessage,
|
652 |
+
setValue,
|
653 |
+
send,
|
654 |
+
],
|
655 |
+
);
|
656 |
+
|
657 |
+
const handleSendMessage = useCallback(
|
658 |
+
async (message: Message) => {
|
659 |
+
if (conversationId !== '') {
|
660 |
+
sendMessage({ message });
|
661 |
+
} else {
|
662 |
+
const data = await setConversation(message.content);
|
663 |
+
if (data.retcode === 0) {
|
664 |
+
const id = data.data.id;
|
665 |
+
sendMessage({ message, currentConversationId: id });
|
666 |
+
}
|
667 |
+
}
|
668 |
+
},
|
669 |
+
[conversationId, setConversation, sendMessage],
|
670 |
+
);
|
671 |
+
|
672 |
+
const { regenerateMessage } = useRegenerateMessage({
|
673 |
+
removeMessagesAfterCurrentMessage,
|
674 |
+
sendMessage,
|
675 |
+
messages: derivedMessages,
|
676 |
+
});
|
677 |
+
|
678 |
+
useEffect(() => {
|
679 |
+
// #1289
|
680 |
+
if (answer.answer && answer?.conversationId === conversationId) {
|
681 |
+
addNewestAnswer(answer);
|
682 |
+
}
|
683 |
+
}, [answer, addNewestAnswer, conversationId]);
|
684 |
+
|
685 |
+
useEffect(() => {
|
686 |
+
// #1289 switch to another conversion window when the last conversion answer doesn't finish.
|
687 |
+
if (conversationId) {
|
688 |
+
setDone(true);
|
689 |
+
}
|
690 |
+
}, [setDone, conversationId]);
|
691 |
+
|
692 |
+
const handlePressEnter = useCallback(
|
693 |
+
(documentIds: string[]) => {
|
694 |
+
if (trim(value) === '') return;
|
695 |
+
const id = uuid();
|
696 |
+
|
697 |
+
addNewestQuestion({
|
698 |
+
content: value,
|
699 |
+
doc_ids: documentIds,
|
700 |
+
id,
|
701 |
+
role: MessageType.User,
|
702 |
+
});
|
703 |
+
if (done) {
|
704 |
+
setValue('');
|
705 |
+
handleSendMessage({
|
706 |
+
id,
|
707 |
+
content: value.trim(),
|
708 |
+
role: MessageType.User,
|
709 |
+
doc_ids: documentIds,
|
710 |
+
});
|
711 |
+
}
|
712 |
+
},
|
713 |
+
[addNewestQuestion, handleSendMessage, done, setValue, value],
|
714 |
+
);
|
715 |
+
|
716 |
+
return {
|
717 |
+
handlePressEnter,
|
718 |
+
handleInputChange,
|
719 |
+
value,
|
720 |
+
setValue,
|
721 |
+
regenerateMessage,
|
722 |
+
sendLoading: !done,
|
723 |
+
loading,
|
724 |
+
ref,
|
725 |
+
derivedMessages,
|
726 |
+
removeMessageById,
|
727 |
+
};
|
728 |
+
};
|
729 |
+
|
730 |
export const useGetFileIcon = () => {
|
731 |
const getFileIcon = (filename: string) => {
|
732 |
const ext: string = getFileExtension(filename);
|
web/src/pages/chat/share/large.tsx
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
import MessageInput from '@/components/message-input';
|
2 |
import MessageItem from '@/components/message-item';
|
3 |
import { MessageType, SharedFrom } from '@/constants/chat';
|
|
|
4 |
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
5 |
import { Flex, Spin } from 'antd';
|
6 |
import { forwardRef } from 'react';
|
7 |
import {
|
8 |
useCreateSharedConversationOnMount,
|
9 |
useGetSharedChatSearchParams,
|
10 |
-
useSelectCurrentSharedConversation,
|
11 |
useSendSharedMessage,
|
12 |
} from '../shared-hooks';
|
13 |
import { buildMessageItemReference } from '../utils';
|
@@ -15,28 +15,17 @@ import styles from './index.less';
|
|
15 |
|
16 |
const ChatContainer = () => {
|
17 |
const { conversationId } = useCreateSharedConversationOnMount();
|
18 |
-
const {
|
19 |
-
currentConversation: conversation,
|
20 |
-
addNewestConversation,
|
21 |
-
removeLatestMessage,
|
22 |
-
ref,
|
23 |
-
loading,
|
24 |
-
setCurrentConversation,
|
25 |
-
addNewestAnswer,
|
26 |
-
} = useSelectCurrentSharedConversation(conversationId);
|
27 |
|
28 |
const {
|
29 |
handlePressEnter,
|
30 |
handleInputChange,
|
31 |
value,
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
setCurrentConversation,
|
38 |
-
addNewestAnswer,
|
39 |
-
);
|
40 |
const sendDisabled = useSendButtonDisabled(value);
|
41 |
const { from } = useGetSharedChatSearchParams();
|
42 |
|
@@ -46,17 +35,23 @@ const ChatContainer = () => {
|
|
46 |
<Flex flex={1} vertical className={styles.messageContainer}>
|
47 |
<div>
|
48 |
<Spin spinning={loading}>
|
49 |
-
{
|
50 |
return (
|
51 |
<MessageItem
|
52 |
key={message.id}
|
53 |
item={message}
|
54 |
nickname="You"
|
55 |
-
reference={buildMessageItemReference(
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
loading={
|
57 |
message.role === MessageType.Assistant &&
|
58 |
sendLoading &&
|
59 |
-
|
60 |
}
|
61 |
index={i}
|
62 |
></MessageItem>
|
|
|
1 |
import MessageInput from '@/components/message-input';
|
2 |
import MessageItem from '@/components/message-item';
|
3 |
import { MessageType, SharedFrom } from '@/constants/chat';
|
4 |
+
import { useFetchNextSharedConversation } from '@/hooks/chat-hooks';
|
5 |
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
6 |
import { Flex, Spin } from 'antd';
|
7 |
import { forwardRef } from 'react';
|
8 |
import {
|
9 |
useCreateSharedConversationOnMount,
|
10 |
useGetSharedChatSearchParams,
|
|
|
11 |
useSendSharedMessage,
|
12 |
} from '../shared-hooks';
|
13 |
import { buildMessageItemReference } from '../utils';
|
|
|
15 |
|
16 |
const ChatContainer = () => {
|
17 |
const { conversationId } = useCreateSharedConversationOnMount();
|
18 |
+
const { data } = useFetchNextSharedConversation(conversationId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
const {
|
21 |
handlePressEnter,
|
22 |
handleInputChange,
|
23 |
value,
|
24 |
+
sendLoading,
|
25 |
+
loading,
|
26 |
+
ref,
|
27 |
+
derivedMessages,
|
28 |
+
} = useSendSharedMessage(conversationId);
|
|
|
|
|
|
|
29 |
const sendDisabled = useSendButtonDisabled(value);
|
30 |
const { from } = useGetSharedChatSearchParams();
|
31 |
|
|
|
35 |
<Flex flex={1} vertical className={styles.messageContainer}>
|
36 |
<div>
|
37 |
<Spin spinning={loading}>
|
38 |
+
{derivedMessages?.map((message, i) => {
|
39 |
return (
|
40 |
<MessageItem
|
41 |
key={message.id}
|
42 |
item={message}
|
43 |
nickname="You"
|
44 |
+
reference={buildMessageItemReference(
|
45 |
+
{
|
46 |
+
message: derivedMessages,
|
47 |
+
reference: data?.data?.reference,
|
48 |
+
},
|
49 |
+
message,
|
50 |
+
)}
|
51 |
loading={
|
52 |
message.role === MessageType.Assistant &&
|
53 |
sendLoading &&
|
54 |
+
derivedMessages?.length - 1 === i
|
55 |
}
|
56 |
index={i}
|
57 |
></MessageItem>
|
web/src/pages/chat/shared-hooks.ts
CHANGED
@@ -3,22 +3,17 @@ import {
|
|
3 |
useCreateNextSharedConversation,
|
4 |
useFetchNextSharedConversation,
|
5 |
} from '@/hooks/chat-hooks';
|
6 |
-
import {
|
7 |
-
|
|
|
|
|
|
|
8 |
import api from '@/utils/api';
|
9 |
-
import { buildMessageUuid } from '@/utils/chat';
|
10 |
import trim from 'lodash/trim';
|
11 |
-
import {
|
12 |
-
Dispatch,
|
13 |
-
SetStateAction,
|
14 |
-
useCallback,
|
15 |
-
useEffect,
|
16 |
-
useState,
|
17 |
-
} from 'react';
|
18 |
import { useSearchParams } from 'umi';
|
19 |
import { v4 as uuid } from 'uuid';
|
20 |
-
import { useHandleMessageInputChange
|
21 |
-
import { IClientConversation, IMessage } from './interface';
|
22 |
|
23 |
export const useCreateSharedConversationOnMount = () => {
|
24 |
const [currentQueryParameters] = useSearchParams();
|
@@ -46,91 +41,30 @@ export const useCreateSharedConversationOnMount = () => {
|
|
46 |
return { conversationId };
|
47 |
};
|
48 |
|
49 |
-
export const
|
50 |
-
const
|
51 |
-
|
52 |
-
const {
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
message: [
|
61 |
-
...(pre.message ?? []),
|
62 |
-
{
|
63 |
-
...message,
|
64 |
-
id: buildMessageUuid(message),
|
65 |
-
} as IMessage,
|
66 |
-
{
|
67 |
-
role: MessageType.Assistant,
|
68 |
-
content: '',
|
69 |
-
id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
|
70 |
-
reference: {},
|
71 |
-
} as IMessage,
|
72 |
-
],
|
73 |
-
};
|
74 |
-
});
|
75 |
-
}, []);
|
76 |
-
|
77 |
-
const addNewestAnswer = useCallback((answer: IAnswer) => {
|
78 |
-
setCurrentConversation((pre) => {
|
79 |
-
const latestMessage = pre.message?.at(-1);
|
80 |
-
|
81 |
-
if (latestMessage) {
|
82 |
-
return {
|
83 |
-
...pre,
|
84 |
-
message: [
|
85 |
-
...pre.message.slice(0, -1),
|
86 |
-
{
|
87 |
-
...latestMessage,
|
88 |
-
content: answer.answer,
|
89 |
-
reference: answer.reference,
|
90 |
-
id: buildMessageUuid({
|
91 |
-
id: answer.id,
|
92 |
-
role: MessageType.Assistant,
|
93 |
-
}),
|
94 |
-
prompt: answer.prompt,
|
95 |
-
} as IMessage,
|
96 |
-
],
|
97 |
-
};
|
98 |
-
}
|
99 |
-
return pre;
|
100 |
-
});
|
101 |
-
}, []);
|
102 |
-
|
103 |
-
const removeLatestMessage = useCallback(() => {
|
104 |
-
setCurrentConversation((pre) => {
|
105 |
-
const nextMessages = pre.message.slice(0, -2);
|
106 |
-
return {
|
107 |
-
...pre,
|
108 |
-
message: nextMessages,
|
109 |
-
};
|
110 |
-
});
|
111 |
-
}, []);
|
112 |
-
|
113 |
-
const fetchConversationOnMount = useCallback(async () => {
|
114 |
-
if (conversationId) {
|
115 |
-
const data = await fetchConversation(conversationId);
|
116 |
-
if (data.retcode === 0) {
|
117 |
-
setCurrentConversation(data.data);
|
118 |
-
}
|
119 |
-
}
|
120 |
-
}, [conversationId, fetchConversation]);
|
121 |
|
122 |
useEffect(() => {
|
123 |
-
|
124 |
-
}, [
|
125 |
|
126 |
return {
|
127 |
-
|
128 |
-
|
|
|
129 |
removeLatestMessage,
|
130 |
loading,
|
131 |
ref,
|
132 |
-
|
133 |
-
addNewestAnswer,
|
134 |
};
|
135 |
};
|
136 |
|
@@ -138,28 +72,28 @@ export const useSendButtonDisabled = (value: string) => {
|
|
138 |
return trim(value) === '';
|
139 |
};
|
140 |
|
141 |
-
export const useSendSharedMessage = (
|
142 |
-
conversation: IClientConversation,
|
143 |
-
addNewestConversation: (message: Partial<Message>, answer?: string) => void,
|
144 |
-
removeLatestMessage: () => void,
|
145 |
-
setCurrentConversation: Dispatch<SetStateAction<IClientConversation>>,
|
146 |
-
addNewestAnswer: (answer: IAnswer) => void,
|
147 |
-
) => {
|
148 |
-
const conversationId = conversation.id;
|
149 |
const { createSharedConversation: setConversation } =
|
150 |
useCreateNextSharedConversation();
|
151 |
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
152 |
-
|
153 |
const { send, answer, done } = useSendMessageWithSse(
|
154 |
api.completeExternalConversation,
|
155 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
|
157 |
const sendMessage = useCallback(
|
158 |
async (message: Message, id?: string) => {
|
159 |
const res = await send({
|
160 |
conversation_id: id ?? conversationId,
|
161 |
quote: false,
|
162 |
-
messages: [...(
|
163 |
});
|
164 |
|
165 |
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
@@ -168,15 +102,7 @@ export const useSendSharedMessage = (
|
|
168 |
removeLatestMessage();
|
169 |
}
|
170 |
},
|
171 |
-
[
|
172 |
-
conversationId,
|
173 |
-
conversation?.message,
|
174 |
-
// fetchConversation,
|
175 |
-
removeLatestMessage,
|
176 |
-
setValue,
|
177 |
-
send,
|
178 |
-
// setCurrentConversation,
|
179 |
-
],
|
180 |
);
|
181 |
|
182 |
const handleSendMessage = useCallback(
|
@@ -206,7 +132,7 @@ export const useSendSharedMessage = (
|
|
206 |
const id = uuid();
|
207 |
if (done) {
|
208 |
setValue('');
|
209 |
-
|
210 |
content: value,
|
211 |
doc_ids: documentIds,
|
212 |
id,
|
@@ -219,14 +145,17 @@ export const useSendSharedMessage = (
|
|
219 |
});
|
220 |
}
|
221 |
},
|
222 |
-
[
|
223 |
);
|
224 |
|
225 |
return {
|
226 |
handlePressEnter,
|
227 |
handleInputChange,
|
228 |
value,
|
229 |
-
|
|
|
|
|
|
|
230 |
};
|
231 |
};
|
232 |
|
|
|
3 |
useCreateNextSharedConversation,
|
4 |
useFetchNextSharedConversation,
|
5 |
} from '@/hooks/chat-hooks';
|
6 |
+
import {
|
7 |
+
useSelectDerivedMessages,
|
8 |
+
useSendMessageWithSse,
|
9 |
+
} from '@/hooks/logic-hooks';
|
10 |
+
import { Message } from '@/interfaces/database/chat';
|
11 |
import api from '@/utils/api';
|
|
|
12 |
import trim from 'lodash/trim';
|
13 |
+
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
import { useSearchParams } from 'umi';
|
15 |
import { v4 as uuid } from 'uuid';
|
16 |
+
import { useHandleMessageInputChange } from './hooks';
|
|
|
17 |
|
18 |
export const useCreateSharedConversationOnMount = () => {
|
19 |
const [currentQueryParameters] = useSearchParams();
|
|
|
41 |
return { conversationId };
|
42 |
};
|
43 |
|
44 |
+
export const useSelectNextSharedMessages = (conversationId: string) => {
|
45 |
+
const { data, loading } = useFetchNextSharedConversation(conversationId);
|
46 |
+
|
47 |
+
const {
|
48 |
+
derivedMessages,
|
49 |
+
ref,
|
50 |
+
setDerivedMessages,
|
51 |
+
addNewestAnswer,
|
52 |
+
addNewestQuestion,
|
53 |
+
removeLatestMessage,
|
54 |
+
} = useSelectDerivedMessages();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
useEffect(() => {
|
57 |
+
setDerivedMessages(data?.data?.message);
|
58 |
+
}, [setDerivedMessages, data]);
|
59 |
|
60 |
return {
|
61 |
+
derivedMessages,
|
62 |
+
addNewestAnswer,
|
63 |
+
addNewestQuestion,
|
64 |
removeLatestMessage,
|
65 |
loading,
|
66 |
ref,
|
67 |
+
setDerivedMessages,
|
|
|
68 |
};
|
69 |
};
|
70 |
|
|
|
72 |
return trim(value) === '';
|
73 |
};
|
74 |
|
75 |
+
export const useSendSharedMessage = (conversationId: string) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
const { createSharedConversation: setConversation } =
|
77 |
useCreateNextSharedConversation();
|
78 |
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
|
|
79 |
const { send, answer, done } = useSendMessageWithSse(
|
80 |
api.completeExternalConversation,
|
81 |
);
|
82 |
+
const {
|
83 |
+
derivedMessages,
|
84 |
+
ref,
|
85 |
+
removeLatestMessage,
|
86 |
+
addNewestAnswer,
|
87 |
+
addNewestQuestion,
|
88 |
+
loading,
|
89 |
+
} = useSelectNextSharedMessages(conversationId);
|
90 |
|
91 |
const sendMessage = useCallback(
|
92 |
async (message: Message, id?: string) => {
|
93 |
const res = await send({
|
94 |
conversation_id: id ?? conversationId,
|
95 |
quote: false,
|
96 |
+
messages: [...(derivedMessages ?? []), message],
|
97 |
});
|
98 |
|
99 |
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
|
|
102 |
removeLatestMessage();
|
103 |
}
|
104 |
},
|
105 |
+
[conversationId, derivedMessages, removeLatestMessage, setValue, send],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
);
|
107 |
|
108 |
const handleSendMessage = useCallback(
|
|
|
132 |
const id = uuid();
|
133 |
if (done) {
|
134 |
setValue('');
|
135 |
+
addNewestQuestion({
|
136 |
content: value,
|
137 |
doc_ids: documentIds,
|
138 |
id,
|
|
|
145 |
});
|
146 |
}
|
147 |
},
|
148 |
+
[addNewestQuestion, done, handleSendMessage, setValue, value],
|
149 |
);
|
150 |
|
151 |
return {
|
152 |
handlePressEnter,
|
153 |
handleInputChange,
|
154 |
value,
|
155 |
+
sendLoading: !done,
|
156 |
+
ref,
|
157 |
+
loading,
|
158 |
+
derivedMessages,
|
159 |
};
|
160 |
};
|
161 |
|
web/src/pages/chat/utils.ts
CHANGED
@@ -36,7 +36,7 @@ export const buildMessageItemReference = (
|
|
36 |
);
|
37 |
const reference = message?.reference
|
38 |
? message?.reference
|
39 |
-
: conversation
|
40 |
|
41 |
return reference;
|
42 |
};
|
|
|
36 |
);
|
37 |
const reference = message?.reference
|
38 |
? message?.reference
|
39 |
+
: (conversation?.reference ?? {})[referenceIndex];
|
40 |
|
41 |
return reference;
|
42 |
};
|
web/src/pages/flow/chat/box.tsx
CHANGED
@@ -6,28 +6,23 @@ import { useClickDrawer, useGetFileIcon } from '@/pages/chat/hooks';
|
|
6 |
import { buildMessageItemReference } from '@/pages/chat/utils';
|
7 |
import { Button, Drawer, Flex, Input, Spin } from 'antd';
|
8 |
|
9 |
-
import {
|
10 |
|
11 |
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
12 |
import styles from './index.less';
|
13 |
|
14 |
const FlowChatBox = () => {
|
15 |
const {
|
16 |
-
|
17 |
-
currentMessages,
|
18 |
-
reference,
|
19 |
-
addNewestAnswer,
|
20 |
-
addNewestQuestion,
|
21 |
-
removeLatestMessage,
|
22 |
-
loading,
|
23 |
-
} = useSelectCurrentMessages();
|
24 |
-
|
25 |
-
const {
|
26 |
handleInputChange,
|
27 |
handlePressEnter,
|
28 |
value,
|
29 |
-
loading
|
30 |
-
|
|
|
|
|
|
|
|
|
31 |
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
32 |
useClickDrawer();
|
33 |
useGetFileIcon();
|
@@ -40,26 +35,26 @@ const FlowChatBox = () => {
|
|
40 |
<Flex flex={1} vertical className={styles.messageContainer}>
|
41 |
<div>
|
42 |
<Spin spinning={loading}>
|
43 |
-
{
|
44 |
return (
|
45 |
<MessageItem
|
46 |
loading={
|
47 |
message.role === MessageType.Assistant &&
|
48 |
sendLoading &&
|
49 |
-
|
50 |
}
|
51 |
key={message.id}
|
52 |
nickname={userInfo.nickname}
|
53 |
avatar={userInfo.avatar}
|
54 |
item={message}
|
55 |
reference={buildMessageItemReference(
|
56 |
-
{ message:
|
57 |
message,
|
58 |
)}
|
59 |
clickDocumentButton={clickDocumentButton}
|
60 |
index={i}
|
61 |
-
regenerateMessage={() => {}}
|
62 |
showLikeButton={false}
|
|
|
63 |
></MessageItem>
|
64 |
);
|
65 |
})}
|
|
|
6 |
import { buildMessageItemReference } from '@/pages/chat/utils';
|
7 |
import { Button, Drawer, Flex, Input, Spin } from 'antd';
|
8 |
|
9 |
+
import { useSendNextMessage } from './hooks';
|
10 |
|
11 |
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
12 |
import styles from './index.less';
|
13 |
|
14 |
const FlowChatBox = () => {
|
15 |
const {
|
16 |
+
sendLoading,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
handleInputChange,
|
18 |
handlePressEnter,
|
19 |
value,
|
20 |
+
loading,
|
21 |
+
ref,
|
22 |
+
derivedMessages,
|
23 |
+
reference,
|
24 |
+
} = useSendNextMessage();
|
25 |
+
|
26 |
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
27 |
useClickDrawer();
|
28 |
useGetFileIcon();
|
|
|
35 |
<Flex flex={1} vertical className={styles.messageContainer}>
|
36 |
<div>
|
37 |
<Spin spinning={loading}>
|
38 |
+
{derivedMessages?.map((message, i) => {
|
39 |
return (
|
40 |
<MessageItem
|
41 |
loading={
|
42 |
message.role === MessageType.Assistant &&
|
43 |
sendLoading &&
|
44 |
+
derivedMessages.length - 1 === i
|
45 |
}
|
46 |
key={message.id}
|
47 |
nickname={userInfo.nickname}
|
48 |
avatar={userInfo.avatar}
|
49 |
item={message}
|
50 |
reference={buildMessageItemReference(
|
51 |
+
{ message: derivedMessages, reference },
|
52 |
message,
|
53 |
)}
|
54 |
clickDocumentButton={clickDocumentButton}
|
55 |
index={i}
|
|
|
56 |
showLikeButton={false}
|
57 |
+
sendLoading={sendLoading}
|
58 |
></MessageItem>
|
59 |
);
|
60 |
})}
|
web/src/pages/flow/chat/hooks.ts
CHANGED
@@ -3,6 +3,7 @@ import { useFetchFlow } from '@/hooks/flow-hooks';
|
|
3 |
import {
|
4 |
useHandleMessageInputChange,
|
5 |
useScrollToBottom,
|
|
|
6 |
useSendMessageWithSse,
|
7 |
} from '@/hooks/logic-hooks';
|
8 |
import { IAnswer, Message } from '@/interfaces/database/chat';
|
@@ -91,6 +92,42 @@ export const useSelectCurrentMessages = () => {
|
|
91 |
};
|
92 |
};
|
93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
export const useSendMessage = (
|
95 |
addNewestQuestion: (message: Message, answer?: string) => void,
|
96 |
removeLatestMessage: () => void,
|
@@ -160,3 +197,84 @@ export const useSendMessage = (
|
|
160 |
loading: !done,
|
161 |
};
|
162 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
import {
|
4 |
useHandleMessageInputChange,
|
5 |
useScrollToBottom,
|
6 |
+
useSelectDerivedMessages,
|
7 |
useSendMessageWithSse,
|
8 |
} from '@/hooks/logic-hooks';
|
9 |
import { IAnswer, Message } from '@/interfaces/database/chat';
|
|
|
92 |
};
|
93 |
};
|
94 |
|
95 |
+
export const useSelectNextMessages = () => {
|
96 |
+
const { id: id } = useParams();
|
97 |
+
const { data: flowDetail, loading } = useFetchFlow();
|
98 |
+
const messages = flowDetail.dsl.messages;
|
99 |
+
const reference = flowDetail.dsl.reference;
|
100 |
+
const {
|
101 |
+
derivedMessages,
|
102 |
+
setDerivedMessages,
|
103 |
+
ref,
|
104 |
+
addNewestQuestion,
|
105 |
+
addNewestAnswer,
|
106 |
+
removeLatestMessage,
|
107 |
+
removeMessageById,
|
108 |
+
removeMessagesAfterCurrentMessage,
|
109 |
+
} = useSelectDerivedMessages();
|
110 |
+
|
111 |
+
useEffect(() => {
|
112 |
+
if (id) {
|
113 |
+
const nextMessages = messages.map((x) => ({ ...x, id: uuid() }));
|
114 |
+
setDerivedMessages(nextMessages);
|
115 |
+
}
|
116 |
+
}, [messages, id, setDerivedMessages]);
|
117 |
+
|
118 |
+
return {
|
119 |
+
reference,
|
120 |
+
loading,
|
121 |
+
derivedMessages,
|
122 |
+
ref,
|
123 |
+
addNewestQuestion,
|
124 |
+
addNewestAnswer,
|
125 |
+
removeLatestMessage,
|
126 |
+
removeMessageById,
|
127 |
+
removeMessagesAfterCurrentMessage,
|
128 |
+
};
|
129 |
+
};
|
130 |
+
|
131 |
export const useSendMessage = (
|
132 |
addNewestQuestion: (message: Message, answer?: string) => void,
|
133 |
removeLatestMessage: () => void,
|
|
|
197 |
loading: !done,
|
198 |
};
|
199 |
};
|
200 |
+
|
201 |
+
export const useSendNextMessage = () => {
|
202 |
+
const {
|
203 |
+
reference,
|
204 |
+
loading,
|
205 |
+
derivedMessages,
|
206 |
+
ref,
|
207 |
+
addNewestQuestion,
|
208 |
+
addNewestAnswer,
|
209 |
+
removeLatestMessage,
|
210 |
+
removeMessageById,
|
211 |
+
} = useSelectNextMessages();
|
212 |
+
const { id: flowId } = useParams();
|
213 |
+
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
214 |
+
const { refetch } = useFetchFlow();
|
215 |
+
|
216 |
+
const { send, answer, done } = useSendMessageWithSse(api.runCanvas);
|
217 |
+
|
218 |
+
const sendMessage = useCallback(
|
219 |
+
async ({ message }: { message: Message; messages?: Message[] }) => {
|
220 |
+
const params: Record<string, unknown> = {
|
221 |
+
id: flowId,
|
222 |
+
};
|
223 |
+
if (message.content) {
|
224 |
+
params.message = message.content;
|
225 |
+
params.message_id = message.id;
|
226 |
+
}
|
227 |
+
const res = await send(params);
|
228 |
+
|
229 |
+
if (receiveMessageError(res)) {
|
230 |
+
antMessage.error(res?.data?.retmsg);
|
231 |
+
|
232 |
+
// cancel loading
|
233 |
+
setValue(message.content);
|
234 |
+
removeLatestMessage();
|
235 |
+
} else {
|
236 |
+
refetch(); // pull the message list after sending the message successfully
|
237 |
+
}
|
238 |
+
},
|
239 |
+
[flowId, removeLatestMessage, setValue, send, refetch],
|
240 |
+
);
|
241 |
+
|
242 |
+
const handleSendMessage = useCallback(
|
243 |
+
async (message: Message) => {
|
244 |
+
sendMessage({ message });
|
245 |
+
},
|
246 |
+
[sendMessage],
|
247 |
+
);
|
248 |
+
|
249 |
+
useEffect(() => {
|
250 |
+
if (answer.answer) {
|
251 |
+
addNewestAnswer(answer);
|
252 |
+
}
|
253 |
+
}, [answer, addNewestAnswer]);
|
254 |
+
|
255 |
+
const handlePressEnter = useCallback(() => {
|
256 |
+
if (trim(value) === '') return;
|
257 |
+
const id = uuid();
|
258 |
+
if (done) {
|
259 |
+
setValue('');
|
260 |
+
handleSendMessage({ id, content: value.trim(), role: MessageType.User });
|
261 |
+
}
|
262 |
+
addNewestQuestion({
|
263 |
+
content: value,
|
264 |
+
id,
|
265 |
+
role: MessageType.User,
|
266 |
+
});
|
267 |
+
}, [addNewestQuestion, handleSendMessage, done, setValue, value]);
|
268 |
+
|
269 |
+
return {
|
270 |
+
handlePressEnter,
|
271 |
+
handleInputChange,
|
272 |
+
value,
|
273 |
+
sendLoading: !done,
|
274 |
+
reference,
|
275 |
+
loading,
|
276 |
+
derivedMessages,
|
277 |
+
ref,
|
278 |
+
removeMessageById,
|
279 |
+
};
|
280 |
+
};
|
web/src/utils/chat.ts
CHANGED
@@ -23,3 +23,12 @@ export const getMessagePureId = (id?: string) => {
|
|
23 |
}
|
24 |
return id;
|
25 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
}
|
24 |
return id;
|
25 |
};
|
26 |
+
|
27 |
+
export const buildMessageListWithUuid = (messages?: Message[]) => {
|
28 |
+
return (
|
29 |
+
messages?.map((x: Message | IMessage) => ({
|
30 |
+
...x,
|
31 |
+
id: buildMessageUuid(x),
|
32 |
+
})) ?? []
|
33 |
+
);
|
34 |
+
};
|