1 Star 0 Fork 0

高亚云/supersonic

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
index.tsx 15.99 KB
一键复制 编辑 原始数据 按行查看 历史
import { updateMessageContainerScroll, isMobile, uuid, setToken } from '../utils/utils';
import {
ForwardRefRenderFunction,
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react';
import MessageContainer from './MessageContainer';
import styles from './style.module.less';
import { ConversationDetailType, MessageItem, MessageTypeEnum, AgentType } from './type';
import { queryAgentList } from './service';
import { useThrottleFn } from 'ahooks';
import Conversation from './Conversation';
import ChatFooter from './ChatFooter';
import classNames from 'classnames';
import { cloneDeep, isBoolean } from 'lodash';
import AgentList from './AgentList';
import MobileAgents from './MobileAgents';
import { HistoryMsgItemType, MsgDataType, SendMsgParamsType } from '../common/type';
import { getHistoryMsg } from '../service';
import ShowCase from '../ShowCase';
import { jsonParse } from '../utils/utils';
import { ConfigProvider, Drawer, Modal, Row, Col, Space, Switch, Tooltip } from 'antd';
import locale from 'antd/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');
type Props = {
token?: string;
agentIds?: number[];
initialAgentId?: number;
chatVisible?: boolean;
noInput?: boolean;
isDeveloper?: boolean;
integrateSystem?: string;
isCopilot?: boolean;
onCurrentAgentChange?: (agent?: AgentType) => void;
onReportMsgEvent?: (msg: string, valid: boolean) => void;
};
const Chat: ForwardRefRenderFunction<any, Props> = (
{
token,
agentIds,
initialAgentId,
chatVisible,
noInput,
isDeveloper,
integrateSystem,
isCopilot,
onCurrentAgentChange,
onReportMsgEvent,
},
ref
) => {
const [messageList, setMessageList] = useState<MessageItem[]>([]);
const [inputMsg, setInputMsg] = useState('');
const [pageNo, setPageNo] = useState(1);
const [hasNextPage, setHasNextPage] = useState(false);
const [historyInited, setHistoryInited] = useState(false);
const [currentConversation, setCurrentConversation] = useState<
ConversationDetailType | undefined
>(isMobile ? { chatId: 0, chatName: '问答' } : undefined);
const [historyVisible, setHistoryVisible] = useState(false);
const [agentList, setAgentList] = useState<AgentType[]>([]);
const [currentAgent, setCurrentAgent] = useState<AgentType>();
const [mobileAgentsVisible, setMobileAgentsVisible] = useState(false);
const [agentListVisible, setAgentListVisible] = useState(true);
const [showCaseVisible, setShowCaseVisible] = useState(false);
const [isSimpleMode, setIsSimpleMode] = useState<boolean>(false);
const [isDebugMode, setIsDebugMode] = useState<boolean>(true);
const conversationRef = useRef<any>();
const chatFooterRef = useRef<any>();
useImperativeHandle(ref, () => ({
sendCopilotMsg,
}));
const sendCopilotMsg = (params: SendMsgParamsType) => {
setAgentListVisible(false);
const { agentId, msg, modelId } = params;
if (currentAgent?.id !== agentId) {
setMessageList([]);
const agent = agentList.find(item => item.id === agentId) || ({} as AgentType);
updateCurrentAgent({ ...agent, initialSendMsgParams: params });
} else {
onSendMsg(msg, messageList, modelId, params);
}
};
const updateAgentConfigMode = (agent: AgentType) => {
const toolConfig = jsonParse(agent?.toolConfig, {});
const { simpleMode, debugMode } = toolConfig;
if (isBoolean(simpleMode)) {
setIsSimpleMode(simpleMode);
} else {
setIsSimpleMode(false);
}
if (isBoolean(debugMode)) {
setIsDebugMode(debugMode);
} else {
setIsDebugMode(true);
}
};
const updateCurrentAgent = (agent?: AgentType) => {
setCurrentAgent(agent);
onCurrentAgentChange?.(agent);
localStorage.setItem('AGENT_ID', `${agent?.id}`);
if (agent) {
updateAgentConfigMode(agent);
}
if (!isCopilot) {
window.history.replaceState({}, '', `${window.location.pathname}?agentId=${agent?.id}`);
}
};
const initAgentList = async () => {
const res = await queryAgentList();
const agentListValue = (res.data || []).filter(
item => item.status === 1 && (agentIds === undefined || agentIds.includes(item.id))
);
setAgentList(agentListValue);
if (agentListValue.length > 0) {
const agentId = initialAgentId || localStorage.getItem('AGENT_ID');
if (agentId) {
const agent = agentListValue.find(item => item.id === +agentId);
updateCurrentAgent(agent || agentListValue[0]);
} else {
updateCurrentAgent(agentListValue[0]);
}
}
};
useEffect(() => {
initAgentList();
}, []);
useEffect(() => {
if (token) {
setToken(token);
}
}, [token]);
useEffect(() => {
if (chatVisible) {
inputFocus();
updateMessageContainerScroll();
}
}, [chatVisible]);
useEffect(() => {
if (!currentConversation) {
return;
}
const { initialMsgParams, isAdd } = currentConversation;
if (isAdd) {
inputFocus();
if (initialMsgParams) {
onSendMsg(initialMsgParams.msg, [], initialMsgParams.modelId, initialMsgParams);
return;
}
sendHelloRsp();
return;
}
updateHistoryMsg(1);
setPageNo(1);
}, [currentConversation]);
useEffect(() => {
if (historyInited) {
const messageContainerEle = document.getElementById('messageContainer');
messageContainerEle?.addEventListener('scroll', handleScroll);
}
return () => {
const messageContainerEle = document.getElementById('messageContainer');
messageContainerEle?.removeEventListener('scroll', handleScroll);
};
}, [historyInited]);
const sendHelloRsp = (agent?: AgentType) => {
if (noInput) {
return;
}
setMessageList([
{
id: uuid(),
type: MessageTypeEnum.AGENT_LIST,
msg: agent?.name || currentAgent?.name || agentList?.[0]?.name,
},
]);
};
const convertHistoryMsg = (list: HistoryMsgItemType[]) => {
return list.map((item: HistoryMsgItemType) => ({
id: item.questionId,
questionId: item.questionId,
type: MessageTypeEnum.QUESTION,
msg: item.queryText,
parseInfos: item.parseInfos,
parseTimeCost: item.parseTimeCost,
msgData: { ...(item.queryResult || {}), similarQueries: item.similarQueries },
score: item.score,
agentId: currentAgent?.id,
}));
};
const updateHistoryMsg = async (page: number) => {
const res = await getHistoryMsg(page, currentConversation!.chatId, 3);
const { hasNextPage, list } = res?.data || { hasNextPage: false, list: [] };
const msgList = [...convertHistoryMsg(list), ...(page === 1 ? [] : messageList)];
setMessageList(msgList);
setHasNextPage(hasNextPage);
if (page === 1) {
if (list.length === 0) {
sendHelloRsp();
}
updateMessageContainerScroll();
setHistoryInited(true);
inputFocus();
} else {
const msgEle = document.getElementById(`${messageList[0]?.id}`);
msgEle?.scrollIntoView();
}
};
const { run: handleScroll } = useThrottleFn(
e => {
if (e.target.scrollTop === 0 && hasNextPage) {
updateHistoryMsg(pageNo + 1);
setPageNo(pageNo + 1);
}
},
{
leading: true,
trailing: true,
wait: 200,
}
);
const inputFocus = () => {
if (!isMobile) {
chatFooterRef.current?.inputFocus();
}
};
const inputBlur = () => {
chatFooterRef.current?.inputBlur();
};
const onSendMsg = async (
msg?: string,
list?: MessageItem[],
modelId?: number,
sendMsgParams?: SendMsgParamsType
) => {
const currentMsg = msg || inputMsg;
if (currentMsg.trim() === '') {
setInputMsg('');
return;
}
const msgAgent = agentList.find(item => currentMsg.indexOf(item.name) === 1);
const certainAgent = currentMsg[0] === '/' && msgAgent;
const agentIdValue = certainAgent ? msgAgent.id : undefined;
const agent = agentList.find(item => item.id === sendMsgParams?.agentId);
if (agent || certainAgent) {
updateCurrentAgent(agent || msgAgent);
}
const msgs = [
...(list || messageList),
{
id: uuid(),
msg: currentMsg,
msgValue: certainAgent
? currentMsg.replace(`/${certainAgent.name}`, '').trim()
: currentMsg,
modelId: modelId === -1 ? undefined : modelId,
agentId: agent?.id || agentIdValue || currentAgent?.id,
type: MessageTypeEnum.QUESTION,
filters: sendMsgParams?.filters,
},
];
setMessageList(msgs);
updateMessageContainerScroll();
setInputMsg('');
};
const onInputMsgChange = (value: string) => {
const inputMsgValue = value || '';
setInputMsg(inputMsgValue);
};
const saveConversationToLocal = (conversation: ConversationDetailType) => {
if (conversation) {
if (conversation.chatId !== -1) {
localStorage.setItem('CONVERSATION_ID', `${conversation.chatId}`);
}
} else {
localStorage.removeItem('CONVERSATION_ID');
}
};
const onSelectConversation = (
conversation: ConversationDetailType,
sendMsgParams?: SendMsgParamsType,
isAdd?: boolean
) => {
setCurrentConversation({
...conversation,
initialMsgParams: sendMsgParams,
isAdd,
});
saveConversationToLocal(conversation);
};
const onMsgDataLoaded = (
data: MsgDataType,
questionId: string | number,
question: string,
valid: boolean,
isRefresh?: boolean
) => {
onReportMsgEvent?.(question, valid);
if (!isMobile) {
conversationRef?.current?.updateData(currentAgent?.id);
}
if (!data) {
return;
}
const msgs = cloneDeep(messageList);
const msg = msgs.find(item => item.id === questionId);
if (msg) {
msg.msgData = data;
setMessageList(msgs);
}
if (!isRefresh) {
updateMessageContainerScroll(`${questionId}`);
}
};
const onToggleHistoryVisible = () => {
setHistoryVisible(!historyVisible);
};
const onAddConversation = () => {
conversationRef.current?.onAddConversation();
inputFocus();
};
const onSelectAgent = (agent: AgentType) => {
if (agent.id === currentAgent?.id) {
return;
}
if (messageList.length === 1 && messageList[0].type === MessageTypeEnum.AGENT_LIST) {
setMessageList([]);
}
updateCurrentAgent(agent);
updateMessageContainerScroll();
};
const sendMsg = (msg: string, modelId?: number) => {
onSendMsg(msg, messageList, modelId);
if (isMobile) {
inputBlur();
}
};
const onCloseConversation = () => {
setHistoryVisible(false);
};
const chatClass = classNames(styles.chat, {
[styles.mobile]: isMobile,
[styles.historyVisible]: historyVisible,
});
return (
<ConfigProvider locale={locale}>
<div className={chatClass}>
<div className={styles.chatSection}>
{!isMobile && agentList.length > 1 && agentListVisible && (
<AgentList
agentList={agentList}
currentAgent={currentAgent}
onSelectAgent={onSelectAgent}
/>
)}
<div className={styles.chatApp}>
{currentConversation && (
<div className={styles.chatBody}>
<div className={styles.chatContent}>
{currentAgent && !isMobile && !noInput && (
<div className={styles.chatHeader}>
<Row style={{ width: '100%' }}>
<Col flex="1 1 200px">
<Space>
<div className={styles.chatHeaderTitle}>{currentAgent.name}</div>
<div className={styles.chatHeaderTip}>{currentAgent.description}</div>
<Tooltip title="精简模式下,问答结果将以文本形式输出">
<Switch
key={currentAgent.id}
style={{ position: 'relative', top: -1 }}
size="small"
value={isSimpleMode}
checkedChildren="精简模式"
unCheckedChildren="精简模式"
onChange={checked => {
setIsSimpleMode(checked);
}}
/>
</Tooltip>
</Space>
</Col>
<Col flex="0 1 118px"></Col>
</Row>
</div>
)}
<MessageContainer
id="messageContainer"
isSimpleMode={isSimpleMode}
isDebugMode={isDebugMode}
messageList={messageList}
chatId={currentConversation?.chatId}
historyVisible={historyVisible}
currentAgent={currentAgent}
chatVisible={chatVisible}
isDeveloper={isDeveloper}
integrateSystem={integrateSystem}
onMsgDataLoaded={onMsgDataLoaded}
onSendMsg={onSendMsg}
/>
{!noInput && (
<ChatFooter
inputMsg={inputMsg}
chatId={currentConversation?.chatId}
agentList={agentList}
currentAgent={currentAgent}
onToggleHistoryVisible={onToggleHistoryVisible}
onInputMsgChange={onInputMsgChange}
onSendMsg={sendMsg}
onAddConversation={onAddConversation}
onSelectAgent={onSelectAgent}
onOpenAgents={() => {
if (isMobile) {
setMobileAgentsVisible(true);
} else {
setAgentListVisible(!agentListVisible);
}
}}
onOpenShowcase={() => {
setShowCaseVisible(!showCaseVisible);
}}
ref={chatFooterRef}
/>
)}
</div>
</div>
)}
</div>
<Conversation
currentAgent={currentAgent}
currentConversation={currentConversation}
historyVisible={historyVisible}
onSelectConversation={onSelectConversation}
onCloseConversation={onCloseConversation}
ref={conversationRef}
/>
{currentAgent &&
(isMobile ? (
<Drawer
title="showcase"
placement="bottom"
height="95%"
open={showCaseVisible}
className={styles.showCaseDrawer}
destroyOnClose
onClose={() => {
setShowCaseVisible(false);
}}
>
<ShowCase agentId={currentAgent.id} onSendMsg={onSendMsg} />
</Drawer>
) : (
<Modal
title="showcase"
width="98%"
open={showCaseVisible}
centered
footer={null}
wrapClassName={styles.showCaseModal}
destroyOnClose
onCancel={() => {
setShowCaseVisible(false);
}}
>
<ShowCase
height="calc(100vh - 140px)"
agentId={currentAgent.id}
onSendMsg={onSendMsg}
/>
</Modal>
))}
</div>
<MobileAgents
open={mobileAgentsVisible}
agentList={agentList}
currentAgent={currentAgent}
onSelectAgent={onSelectAgent}
onClose={() => {
setMobileAgentsVisible(false);
}}
/>
</div>
</ConfigProvider>
);
};
export default forwardRef(Chat);
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/Jakarta-EE/supersonic.git
git@gitee.com:Jakarta-EE/supersonic.git
Jakarta-EE
supersonic
supersonic
master

搜索帮助