mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-13 13:07:32 +00:00
203 lines
6.2 KiB
TypeScript
203 lines
6.2 KiB
TypeScript
import Text from './components/Text';
|
|
import { memo, useCallback, useEffect, useState } from 'react';
|
|
import { isEqual } from 'lodash';
|
|
import { ChatItem } from 'supersonic-chat-sdk';
|
|
import type { MsgDataType } from 'supersonic-chat-sdk';
|
|
import { MessageItem, MessageTypeEnum } from './type';
|
|
import Plugin from './components/Plugin';
|
|
import { updateMessageContainerScroll } from '@/utils/utils';
|
|
import styles from './style.less';
|
|
|
|
type Props = {
|
|
id: string;
|
|
chatId: number;
|
|
messageList: MessageItem[];
|
|
isMobileMode?: boolean;
|
|
conversationCollapsed: boolean;
|
|
copilotFullscreen?: boolean;
|
|
onClickMessageContainer: () => void;
|
|
onMsgDataLoaded: (
|
|
data: MsgDataType,
|
|
questionId: string | number,
|
|
question: string,
|
|
valid: boolean,
|
|
) => void;
|
|
onCheckMore: (data: MsgDataType) => void;
|
|
onApplyAuth: (model: string) => void;
|
|
};
|
|
|
|
const MessageContainer: React.FC<Props> = ({
|
|
id,
|
|
chatId,
|
|
messageList,
|
|
isMobileMode,
|
|
conversationCollapsed,
|
|
copilotFullscreen,
|
|
onClickMessageContainer,
|
|
onMsgDataLoaded,
|
|
onCheckMore,
|
|
onApplyAuth,
|
|
}) => {
|
|
const [triggerResize, setTriggerResize] = useState(false);
|
|
|
|
const onResize = useCallback(() => {
|
|
setTriggerResize(true);
|
|
setTimeout(() => {
|
|
setTriggerResize(false);
|
|
}, 0);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
window.addEventListener('resize', onResize);
|
|
return () => {
|
|
window.removeEventListener('resize', onResize);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
onResize();
|
|
}, [conversationCollapsed]);
|
|
|
|
useEffect(() => {
|
|
onResize();
|
|
updateMessageContainerScroll();
|
|
}, [copilotFullscreen]);
|
|
|
|
const getFollowQuestions = (index: number) => {
|
|
const followQuestions: string[] = [];
|
|
const currentMsg = messageList[index];
|
|
const currentMsgData = currentMsg.msgData;
|
|
const msgs = messageList.slice(0, index).reverse();
|
|
|
|
for (let i = 0; i < msgs.length; i++) {
|
|
const msg = msgs[i];
|
|
const msgModelId = msg.msgData?.chatContext?.modelId;
|
|
const msgEntityId = msg.msgData?.entityInfo?.entityId;
|
|
const currentMsgModelId = currentMsgData?.chatContext?.modelId;
|
|
const currentMsgEntityId = currentMsgData?.entityInfo?.entityId;
|
|
|
|
if (
|
|
(msg.type === MessageTypeEnum.QUESTION || msg.type === MessageTypeEnum.PLUGIN) &&
|
|
!!currentMsgModelId &&
|
|
msgModelId === currentMsgModelId &&
|
|
msgEntityId === currentMsgEntityId &&
|
|
msg.msg
|
|
) {
|
|
followQuestions.push(msg.msg);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return followQuestions;
|
|
};
|
|
|
|
const getFilters = (modelId?: number, entityId?: string) => {
|
|
if (!modelId || !entityId) {
|
|
return undefined;
|
|
}
|
|
return [
|
|
{
|
|
value: entityId,
|
|
},
|
|
];
|
|
};
|
|
|
|
return (
|
|
<div id={id} className={styles.messageContainer} onClick={onClickMessageContainer}>
|
|
<div className={styles.messageList}>
|
|
{messageList.map((msgItem: MessageItem, index: number) => {
|
|
const {
|
|
id: msgId,
|
|
modelId,
|
|
entityId,
|
|
type,
|
|
msg,
|
|
msgValue,
|
|
identityMsg,
|
|
msgData,
|
|
score,
|
|
isHistory,
|
|
parseOptions,
|
|
} = msgItem;
|
|
|
|
const followQuestions = getFollowQuestions(index);
|
|
|
|
return (
|
|
<div key={msgId} id={`${msgId}`} className={styles.messageItem}>
|
|
{type === MessageTypeEnum.TEXT && <Text position="left" data={msg} />}
|
|
{type === MessageTypeEnum.QUESTION && (
|
|
<>
|
|
<Text position="right" data={msg} />
|
|
{identityMsg && <Text position="left" data={identityMsg} />}
|
|
<ChatItem
|
|
msg={msgValue || msg || ''}
|
|
msgData={msgData}
|
|
conversationId={chatId}
|
|
modelId={modelId}
|
|
filter={getFilters(modelId, entityId)}
|
|
isLastMessage={index === messageList.length - 1}
|
|
isMobileMode={isMobileMode}
|
|
triggerResize={triggerResize}
|
|
onMsgDataLoaded={(data: MsgDataType, valid: boolean) => {
|
|
onMsgDataLoaded(data, msgId, msgValue || msg || '', valid);
|
|
}}
|
|
onUpdateMessageScroll={updateMessageContainerScroll}
|
|
/>
|
|
</>
|
|
)}
|
|
{type === MessageTypeEnum.PARSE_OPTIONS && (
|
|
<ChatItem
|
|
msg={msgValue || msg || ''}
|
|
conversationId={chatId}
|
|
modelId={modelId}
|
|
filter={getFilters(modelId, entityId)}
|
|
isLastMessage={index === messageList.length - 1}
|
|
isMobileMode={isMobileMode}
|
|
triggerResize={triggerResize}
|
|
parseOptions={parseOptions}
|
|
onMsgDataLoaded={(data: MsgDataType, valid: boolean) => {
|
|
onMsgDataLoaded(data, msgId, msgValue || msg || '', valid);
|
|
}}
|
|
onUpdateMessageScroll={updateMessageContainerScroll}
|
|
/>
|
|
)}
|
|
{type === MessageTypeEnum.PLUGIN && (
|
|
<>
|
|
<Plugin
|
|
id={msgId}
|
|
followQuestions={followQuestions}
|
|
data={msgData!}
|
|
scoreValue={score}
|
|
msg={msgValue || msg || ''}
|
|
isHistory={isHistory}
|
|
isLastMessage={index === messageList.length - 1}
|
|
isMobileMode={isMobileMode}
|
|
onReportLoaded={(height: number) => {
|
|
updateMessageContainerScroll(true, height);
|
|
}}
|
|
onCheckMore={onCheckMore}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function areEqual(prevProps: Props, nextProps: Props) {
|
|
if (
|
|
prevProps.id === nextProps.id &&
|
|
isEqual(prevProps.messageList, nextProps.messageList) &&
|
|
prevProps.conversationCollapsed === nextProps.conversationCollapsed &&
|
|
prevProps.copilotFullscreen === nextProps.copilotFullscreen
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export default memo(MessageContainer, areEqual);
|