mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-12 20:51:48 +00:00
(feature)(webapp) add display of time consumption at each stage (#331)
This commit is contained in:
@@ -76,6 +76,7 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
score,
|
score,
|
||||||
identityMsg,
|
identityMsg,
|
||||||
parseInfos,
|
parseInfos,
|
||||||
|
parseTimeCost,
|
||||||
msgData,
|
msgData,
|
||||||
filters,
|
filters,
|
||||||
} = msgItem;
|
} = msgItem;
|
||||||
@@ -93,13 +94,13 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
<ChatItem
|
<ChatItem
|
||||||
msg={msgValue || msg || ''}
|
msg={msgValue || msg || ''}
|
||||||
parseInfos={parseInfos}
|
parseInfos={parseInfos}
|
||||||
|
parseTimeCostValue={parseTimeCost}
|
||||||
msgData={msgData}
|
msgData={msgData}
|
||||||
conversationId={chatId}
|
conversationId={chatId}
|
||||||
modelId={modelId}
|
modelId={modelId}
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
score={score}
|
score={score}
|
||||||
filter={filters}
|
filter={filters}
|
||||||
isLastMessage={index === messageList.length - 1}
|
|
||||||
triggerResize={triggerResize}
|
triggerResize={triggerResize}
|
||||||
isDeveloper={isDeveloper}
|
isDeveloper={isDeveloper}
|
||||||
integrateSystem={integrateSystem}
|
integrateSystem={integrateSystem}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import MobileAgents from './MobileAgents';
|
|||||||
import { HistoryMsgItemType, MsgDataType, SendMsgParamsType } from '../common/type';
|
import { HistoryMsgItemType, MsgDataType, SendMsgParamsType } from '../common/type';
|
||||||
import { getHistoryMsg } from '../service';
|
import { getHistoryMsg } from '../service';
|
||||||
import ShowCase from '../ShowCase';
|
import ShowCase from '../ShowCase';
|
||||||
import { Modal } from 'antd';
|
import { Drawer, Modal } from 'antd';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
token?: string;
|
token?: string;
|
||||||
@@ -176,6 +176,7 @@ const Chat: ForwardRefRenderFunction<any, Props> = (
|
|||||||
type: MessageTypeEnum.QUESTION,
|
type: MessageTypeEnum.QUESTION,
|
||||||
msg: item.queryText,
|
msg: item.queryText,
|
||||||
parseInfos: item.parseInfos,
|
parseInfos: item.parseInfos,
|
||||||
|
parseTimeCost: item.parseTimeCost,
|
||||||
msgData: item.queryResult,
|
msgData: item.queryResult,
|
||||||
score: item.score,
|
score: item.score,
|
||||||
agentId: currentAgent?.id,
|
agentId: currentAgent?.id,
|
||||||
@@ -421,23 +422,41 @@ const Chat: ForwardRefRenderFunction<any, Props> = (
|
|||||||
onCloseConversation={onCloseConversation}
|
onCloseConversation={onCloseConversation}
|
||||||
ref={conversationRef}
|
ref={conversationRef}
|
||||||
/>
|
/>
|
||||||
{currentAgent && (
|
{currentAgent &&
|
||||||
<Modal
|
(isMobile ? (
|
||||||
title="showcase"
|
<Drawer
|
||||||
width="98%"
|
title="showcase"
|
||||||
open={showCaseVisible}
|
placement="bottom"
|
||||||
centered
|
height="95%"
|
||||||
footer={null}
|
open={showCaseVisible}
|
||||||
wrapClassName={styles.showCaseModal}
|
className={styles.showCaseDrawer}
|
||||||
onCancel={() => {
|
destroyOnClose
|
||||||
setShowCaseVisible(false);
|
onClose={() => {
|
||||||
}}
|
setShowCaseVisible(false);
|
||||||
>
|
}}
|
||||||
<div className={styles.showCase}>
|
>
|
||||||
<ShowCase agentId={currentAgent.id} onSendMsg={onSendMsg} />
|
<ShowCase agentId={currentAgent.id} onSendMsg={onSendMsg} />
|
||||||
</div>
|
</Drawer>
|
||||||
</Modal>
|
) : (
|
||||||
)}
|
<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>
|
</div>
|
||||||
<MobileAgents
|
<MobileAgents
|
||||||
open={mobileAgentsVisible}
|
open={mobileAgentsVisible}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
width: 600px;
|
width: 600px;
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: var(--text-color-fourth);
|
color: var(--text-color-third);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -79,17 +79,30 @@
|
|||||||
|
|
||||||
.showCaseModal {
|
.showCaseModal {
|
||||||
:global {
|
:global {
|
||||||
.ant-modal-body {
|
.ant-modal-content {
|
||||||
padding: 20px 0 !important;
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
padding: 20px 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.showCase {
|
.showCaseDrawer {
|
||||||
height: calc(100vh - 140px);
|
:global {
|
||||||
padding: 0 20px;
|
.ant-drawer-content {
|
||||||
overflow-y: auto;
|
border-top-left-radius: 12px;
|
||||||
padding-bottom: 2px;
|
border-top-right-radius: 12px;
|
||||||
|
.ant-drawer-body {
|
||||||
|
padding: 4px 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:global {
|
:global {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ChatContextType, MsgDataType, SendMsgParamsType } from "../common/type";
|
import { ChatContextType, MsgDataType, ParseTimeCostType, SendMsgParamsType } from "../common/type";
|
||||||
|
|
||||||
export enum MessageTypeEnum {
|
export enum MessageTypeEnum {
|
||||||
TEXT = 'text', // 指标文本
|
TEXT = 'text', // 指标文本
|
||||||
@@ -23,6 +23,7 @@ export type MessageItem = {
|
|||||||
agentId?: number;
|
agentId?: number;
|
||||||
entityId?: string;
|
entityId?: string;
|
||||||
parseInfos?: ChatContextType[];
|
parseInfos?: ChatContextType[];
|
||||||
|
parseTimeCost?: ParseTimeCostType;
|
||||||
msgData?: MsgDataType;
|
msgData?: MsgDataType;
|
||||||
quote?: string;
|
quote?: string;
|
||||||
score?: number;
|
score?: number;
|
||||||
|
|||||||
@@ -1,62 +1,117 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import styles from './style.module.less';
|
import styles from './style.module.less';
|
||||||
import { ShowCaseMapType } from './type';
|
import { ShowCaseItemType } from './type';
|
||||||
import { queryShowCase } from './service';
|
import { queryShowCase } from './service';
|
||||||
import Text from '../Chat/components/Text';
|
import Text from '../Chat/components/Text';
|
||||||
import ChatItem from '../components/ChatItem';
|
import ChatItem from '../components/ChatItem';
|
||||||
import { HistoryMsgItemType } from '../common/type';
|
import { HistoryMsgItemType } from '../common/type';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { isMobile } from '../utils/utils';
|
||||||
|
import { useThrottleFn } from 'ahooks';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
height?: number | string;
|
||||||
agentId: number;
|
agentId: number;
|
||||||
onSendMsg?: (msg: string) => void;
|
onSendMsg?: (msg: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShowCase: React.FC<Props> = ({ agentId, onSendMsg }) => {
|
const ShowCase: React.FC<Props> = ({ height, agentId, onSendMsg }) => {
|
||||||
const [showCaseMap, setShowCaseMap] = useState<ShowCaseMapType>({});
|
const [showCaseList, setShowCaseList] = useState<ShowCaseItemType[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [pageNo, setPageNo] = useState(1);
|
||||||
|
|
||||||
const updateData = async () => {
|
const showcaseRef = useRef<any>(null);
|
||||||
setLoading(true);
|
|
||||||
const res = await queryShowCase(agentId, 1, 30);
|
const updateData = async (pageNoValue: number) => {
|
||||||
setLoading(false);
|
if (pageNoValue === 1) {
|
||||||
setShowCaseMap(res.data.showCaseMap);
|
setLoading(true);
|
||||||
|
}
|
||||||
|
const res = await queryShowCase(agentId, pageNoValue, isMobile ? 10 : 20);
|
||||||
|
if (pageNoValue === 1) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
const showCaseMapRes: any = res.data.showCaseMap;
|
||||||
|
const list = Object.keys(showCaseMapRes)
|
||||||
|
.reduce((result: ShowCaseItemType[], key: string) => {
|
||||||
|
result.push({ msgList: showCaseMapRes[key], caseId: key });
|
||||||
|
return result;
|
||||||
|
}, [])
|
||||||
|
.sort((a, b) => {
|
||||||
|
return (b.msgList?.[0]?.score || 3) - (a.msgList?.[0]?.score || 3);
|
||||||
|
});
|
||||||
|
setShowCaseList(pageNoValue === 1 ? list : [...showCaseList, ...list]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { run: handleScroll } = useThrottleFn(
|
||||||
|
e => {
|
||||||
|
const bottom =
|
||||||
|
e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight ||
|
||||||
|
e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight + 0.5;
|
||||||
|
if (bottom) {
|
||||||
|
updateData(pageNo + 1);
|
||||||
|
setPageNo(pageNo + 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leading: true,
|
||||||
|
trailing: true,
|
||||||
|
wait: 200,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isMobile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const el = showcaseRef.current;
|
||||||
|
el?.addEventListener('scroll', handleScroll);
|
||||||
|
return () => {
|
||||||
|
el.removeEventListener('scroll', handleScroll);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (agentId) {
|
if (agentId) {
|
||||||
updateData();
|
setShowCaseList([]);
|
||||||
|
updateData(1);
|
||||||
|
setPageNo(1);
|
||||||
}
|
}
|
||||||
}, [agentId]);
|
}, [agentId]);
|
||||||
|
|
||||||
|
const showCaseClass = classNames(styles.showCase, { [styles.mobile]: isMobile });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Spin spinning={loading} size="large">
|
<Spin spinning={loading} size="large">
|
||||||
<div className={styles.showCase}>
|
<div className={showCaseClass} style={{ height }} ref={showcaseRef}>
|
||||||
{Object.keys(showCaseMap || {}).map(key => {
|
<div className={styles.showCaseContent}>
|
||||||
const showCaseItem = showCaseMap?.[key] || [];
|
{showCaseList.map(showCaseItem => {
|
||||||
return (
|
return (
|
||||||
<div key={key} className={styles.showCaseItem}>
|
<div key={showCaseItem.caseId} className={styles.showCaseItem}>
|
||||||
{showCaseItem
|
{showCaseItem.msgList
|
||||||
.filter((chatItem: HistoryMsgItemType) => !!chatItem.queryResult)
|
.filter((chatItem: HistoryMsgItemType) => !!chatItem.queryResult)
|
||||||
.slice(0, 10)
|
.slice(0, 1)
|
||||||
.map((chatItem: HistoryMsgItemType) => {
|
.map((chatItem: HistoryMsgItemType) => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.showCaseChatItem} key={chatItem.questionId}>
|
<div className={styles.showCaseChatItem} key={chatItem.questionId}>
|
||||||
<Text position="right" data={chatItem.queryText} anonymousUser />
|
<Text position="right" data={chatItem.queryText} anonymousUser />
|
||||||
<ChatItem
|
<ChatItem
|
||||||
msg={chatItem.queryText}
|
msg={chatItem.queryText}
|
||||||
msgData={chatItem.queryResult}
|
parseInfos={chatItem.parseInfos}
|
||||||
conversationId={chatItem.chatId}
|
msgData={chatItem.queryResult}
|
||||||
agentId={agentId}
|
conversationId={chatItem.chatId}
|
||||||
integrateSystem="showcase"
|
agentId={agentId}
|
||||||
onSendMsg={onSendMsg}
|
integrateSystem="showcase"
|
||||||
/>
|
score={chatItem.score}
|
||||||
</div>
|
onSendMsg={onSendMsg}
|
||||||
);
|
/>
|
||||||
})}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,27 +1,46 @@
|
|||||||
.showCase {
|
.showCase {
|
||||||
column-count: 2;
|
position: relative;
|
||||||
column-gap: 20px;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 400px;
|
padding: 0 20px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
|
||||||
.showCaseItem {
|
.showCaseContent {
|
||||||
display: flex;
|
column-count: 2;
|
||||||
flex-direction: column;
|
column-gap: 20px;
|
||||||
row-gap: 12px;
|
|
||||||
padding: 12px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
max-height: 800px;
|
|
||||||
overflow-y: auto;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.14), 0 0 2px rgba(0, 0, 0, 0.12);
|
|
||||||
background: linear-gradient(180deg, rgba(23, 74, 228, 0) 29.44%, rgba(23, 74, 228, 0.06) 100%),
|
|
||||||
linear-gradient(90deg, #f3f3f7 0%, #f3f3f7 20%, #ebf0f9 60%, #f3f3f7 80%, #f3f3f7 100%);
|
|
||||||
|
|
||||||
.showCaseChatItem {
|
.showcaseLoading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showCaseItem {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
row-gap: 12px;
|
row-gap: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.14), 0 0 2px rgba(0, 0, 0, 0.12);
|
||||||
|
background: linear-gradient(180deg, rgba(23, 74, 228, 0) 29.44%, rgba(23, 74, 228, 0.06) 100%),
|
||||||
|
linear-gradient(90deg, #f3f3f7 0%, #f3f3f7 20%, #ebf0f9 60%, #f3f3f7 80%, #f3f3f7 100%);
|
||||||
|
|
||||||
|
.showCaseChatItem {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mobile {
|
||||||
|
padding: 0 4px;
|
||||||
|
.showCaseContent {
|
||||||
|
column-count: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import { HistoryMsgItemType } from "../common/type";
|
|||||||
|
|
||||||
export type ShowCaseMapType = Record<number, HistoryMsgItemType[]>;
|
export type ShowCaseMapType = Record<number, HistoryMsgItemType[]>;
|
||||||
|
|
||||||
|
export type ShowCaseItemType = {
|
||||||
|
caseId: string;
|
||||||
|
msgList: HistoryMsgItemType[];
|
||||||
|
}
|
||||||
|
|
||||||
export type ShowCaseType = {
|
export type ShowCaseType = {
|
||||||
showCaseMap: ShowCaseMapType,
|
showCaseMap: ShowCaseMapType,
|
||||||
current: number,
|
current: number,
|
||||||
|
|||||||
@@ -136,7 +136,8 @@ export type MsgDataType = {
|
|||||||
queryState: string;
|
queryState: string;
|
||||||
queryText: string;
|
queryText: string;
|
||||||
response: PluginResonseType;
|
response: PluginResonseType;
|
||||||
parseOptions?: ChatContextType[];
|
parseInfos?: ChatContextType[];
|
||||||
|
queryTimeCost?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum ParseStateEnum {
|
export enum ParseStateEnum {
|
||||||
@@ -211,6 +212,7 @@ export type HistoryMsgItemType = {
|
|||||||
questionId: number;
|
questionId: number;
|
||||||
queryText: string;
|
queryText: string;
|
||||||
parseInfos: ChatContextType[];
|
parseInfos: ChatContextType[];
|
||||||
|
parseTimeCost: ParseTimeCostType;
|
||||||
queryResult: MsgDataType;
|
queryResult: MsgDataType;
|
||||||
chatId: number;
|
chatId: number;
|
||||||
createTime: string;
|
createTime: string;
|
||||||
@@ -242,3 +244,8 @@ export type SimilarQuestionType = {
|
|||||||
// parseId: number;
|
// parseId: number;
|
||||||
queryText: string;
|
queryText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ParseTimeCostType = {
|
||||||
|
parseTime: number;
|
||||||
|
sqlTime: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
import { CheckCircleFilled } from '@ant-design/icons';
|
||||||
import { PREFIX_CLS } from '../../common/constants';
|
import { PREFIX_CLS } from '../../common/constants';
|
||||||
import { MsgDataType } from '../../common/type';
|
import { MsgDataType } from '../../common/type';
|
||||||
import ChatMsg from '../ChatMsg';
|
import ChatMsg from '../ChatMsg';
|
||||||
@@ -17,7 +17,7 @@ type Props = {
|
|||||||
renderCustomExecuteNode?: boolean;
|
renderCustomExecuteNode?: boolean;
|
||||||
data?: MsgDataType;
|
data?: MsgDataType;
|
||||||
triggerResize?: boolean;
|
triggerResize?: boolean;
|
||||||
onRefresh: () => void;
|
isDeveloper?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExecuteItem: React.FC<Props> = ({
|
const ExecuteItem: React.FC<Props> = ({
|
||||||
@@ -30,7 +30,7 @@ const ExecuteItem: React.FC<Props> = ({
|
|||||||
renderCustomExecuteNode,
|
renderCustomExecuteNode,
|
||||||
data,
|
data,
|
||||||
triggerResize,
|
triggerResize,
|
||||||
onRefresh,
|
isDeveloper,
|
||||||
}) => {
|
}) => {
|
||||||
const prefixCls = `${PREFIX_CLS}-item`;
|
const prefixCls = `${PREFIX_CLS}-item`;
|
||||||
|
|
||||||
@@ -49,19 +49,20 @@ const ExecuteItem: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reloadNode = (
|
|
||||||
<Button className={`${prefixCls}-reload`} size="small" onClick={onRefresh}>
|
|
||||||
<ReloadOutlined />
|
|
||||||
重新查询
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (executeLoading) {
|
if (executeLoading) {
|
||||||
return getNodeTip('数据查询中');
|
return getNodeTip('数据查询中');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (executeTip) {
|
if (executeTip) {
|
||||||
return getNodeTip(<>数据查询失败:{reloadNode}</>, executeTip);
|
return getNodeTip(
|
||||||
|
<>
|
||||||
|
数据查询失败
|
||||||
|
{data?.queryTimeCost && isDeveloper && (
|
||||||
|
<span className={`${prefixCls}-title-tip`}>(耗时: {data.queryTimeCost}ms)</span>
|
||||||
|
)}
|
||||||
|
</>,
|
||||||
|
executeTip
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -73,8 +74,10 @@ const ExecuteItem: React.FC<Props> = ({
|
|||||||
<div className={`${prefixCls}-title-bar`}>
|
<div className={`${prefixCls}-title-bar`}>
|
||||||
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
||||||
<div className={`${prefixCls}-step-title`}>
|
<div className={`${prefixCls}-step-title`}>
|
||||||
数据查询:
|
数据查询
|
||||||
{reloadNode}
|
{data?.queryTimeCost && isDeveloper && (
|
||||||
|
<span className={`${prefixCls}-title-tip`}>(耗时: {data.queryTimeCost}ms)</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${prefixCls}-content-container`}>
|
<div className={`${prefixCls}-content-container`}>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { Select, Spin, InputNumber } from 'antd';
|
import { Select, Spin, InputNumber, DatePicker } from 'antd';
|
||||||
import { PREFIX_CLS } from '../../common/constants';
|
import { PREFIX_CLS } from '../../common/constants';
|
||||||
import { ChatContextType, FilterItemType } from '../../common/type';
|
import { ChatContextType, FilterItemType } from '../../common/type';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { queryDimensionValues } from '../../service';
|
import { queryDimensionValues } from '../../service';
|
||||||
import { debounce, isArray } from 'lodash';
|
import { debounce, isArray } from 'lodash';
|
||||||
import SwicthEntity from './SwitchEntity';
|
import SwicthEntity from './SwitchEntity';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
modelId: number;
|
modelId: number;
|
||||||
filters: FilterItemType[];
|
filters: FilterItemType[];
|
||||||
filter: FilterItemType;
|
filter: FilterItemType;
|
||||||
|
index: number;
|
||||||
chatContext: ChatContextType;
|
chatContext: ChatContextType;
|
||||||
agentId?: number;
|
agentId?: number;
|
||||||
entityAlias?: string;
|
entityAlias?: string;
|
||||||
@@ -22,6 +24,7 @@ const FilterItem: React.FC<Props> = ({
|
|||||||
modelId,
|
modelId,
|
||||||
filters,
|
filters,
|
||||||
filter,
|
filter,
|
||||||
|
index,
|
||||||
chatContext,
|
chatContext,
|
||||||
agentId,
|
agentId,
|
||||||
entityAlias,
|
entityAlias,
|
||||||
@@ -44,7 +47,7 @@ const FilterItem: React.FC<Props> = ({
|
|||||||
''
|
''
|
||||||
);
|
);
|
||||||
setOptions(
|
setOptions(
|
||||||
data?.resultList.map((item: any) => ({
|
data?.resultList?.map((item: any) => ({
|
||||||
label: item[filter.bizName],
|
label: item[filter.bizName],
|
||||||
value: item[filter.bizName],
|
value: item[filter.bizName],
|
||||||
})) || []
|
})) || []
|
||||||
@@ -87,8 +90,8 @@ const FilterItem: React.FC<Props> = ({
|
|||||||
}, [queryDimensionValues]);
|
}, [queryDimensionValues]);
|
||||||
|
|
||||||
const onOperatorChange = (value: string) => {
|
const onOperatorChange = (value: string) => {
|
||||||
const newFilters = filters.map(item => {
|
const newFilters = filters.map((item, indexValue) => {
|
||||||
if (item.bizName === filter.bizName) {
|
if (item.bizName === filter.bizName && index === indexValue) {
|
||||||
item.operator = value;
|
item.operator = value;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
@@ -97,8 +100,8 @@ const FilterItem: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onChange = (value: string | string[] | number | null) => {
|
const onChange = (value: string | string[] | number | null) => {
|
||||||
const newFilters = filters.map(item => {
|
const newFilters = filters.map((item, indexValue) => {
|
||||||
if (item.bizName === filter.bizName) {
|
if (item.bizName === filter.bizName && index === indexValue) {
|
||||||
item.value =
|
item.value =
|
||||||
typeof filter.value === 'number' || filter.value === null
|
typeof filter.value === 'number' || filter.value === null
|
||||||
? value
|
? value
|
||||||
@@ -123,28 +126,46 @@ const FilterItem: React.FC<Props> = ({
|
|||||||
onFiltersChange(newFilters);
|
onFiltersChange(newFilters);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDateChange = (_: any, date: string) => {
|
||||||
|
console.log('onDateChange', date);
|
||||||
|
const newFilters = filters.map((item, indexValue) => {
|
||||||
|
if (item.bizName === filter.bizName && index === indexValue) {
|
||||||
|
item.value = date;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
onFiltersChange(newFilters);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={prefixCls}>
|
<span className={prefixCls}>
|
||||||
<span className={`${prefixCls}-filter-name`}>{filter.name}:</span>
|
<span className={`${prefixCls}-filter-name`}>{filter.name}:</span>
|
||||||
{(typeof filter.value === 'number' || filter.value === null) &&
|
{(typeof filter.value === 'number' ||
|
||||||
!filter.bizName?.includes('_id') ? (
|
filter.value === null ||
|
||||||
<>
|
(filter.operator && !['IN', '=', 'LIKE'].includes(filter.operator))) &&
|
||||||
|
!filter.bizName?.includes('_id') && (
|
||||||
<Select
|
<Select
|
||||||
options={[
|
options={[
|
||||||
|
{ label: '大于等于', value: '>=' },
|
||||||
{ label: '大于', value: '>' },
|
{ label: '大于', value: '>' },
|
||||||
{ label: '等于', value: '=' },
|
{ label: '等于', value: '=' },
|
||||||
|
{ label: '小于等于', value: '<=' },
|
||||||
{ label: '小于', value: '<' },
|
{ label: '小于', value: '<' },
|
||||||
]}
|
]}
|
||||||
className={`${prefixCls}-operator-control`}
|
className={`${prefixCls}-operator-control`}
|
||||||
value={filter.operator}
|
value={filter.operator}
|
||||||
onChange={onOperatorChange}
|
onChange={onOperatorChange}
|
||||||
/>
|
/>
|
||||||
<InputNumber
|
)}
|
||||||
className={`${prefixCls}-input-number-control`}
|
{(typeof filter.value === 'number' || filter.value === null) &&
|
||||||
value={filter.value}
|
!filter.bizName?.includes('_id') ? (
|
||||||
onChange={onChange}
|
<InputNumber
|
||||||
/>
|
className={`${prefixCls}-input-number-control`}
|
||||||
</>
|
value={filter.value}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
) : typeof filter.value === 'string' && moment(filter.value, 'YYYY-MM-DD').isValid() ? (
|
||||||
|
<DatePicker value={moment(filter.value)} onChange={onDateChange} allowClear={false} />
|
||||||
) : (typeof filter.value === 'string' || isArray(filter.value)) &&
|
) : (typeof filter.value === 'string' || isArray(filter.value)) &&
|
||||||
!filter.bizName?.includes('_id') ? (
|
!filter.bizName?.includes('_id') ? (
|
||||||
<Select
|
<Select
|
||||||
@@ -173,7 +194,9 @@ const FilterItem: React.FC<Props> = ({
|
|||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span className={`${prefixCls}-filter-value`}>{filter.value}</span>
|
<span className={`${prefixCls}-filter-value`}>
|
||||||
|
{typeof filter.value !== 'object' ? filter.value : ''}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import { AGG_TYPE_MAP, PREFIX_CLS } from '../../common/constants';
|
import { AGG_TYPE_MAP, PREFIX_CLS } from '../../common/constants';
|
||||||
import { ChatContextType, DateInfoType, EntityInfoType, FilterItemType } from '../../common/type';
|
import { ChatContextType, DateInfoType, EntityInfoType, FilterItemType } from '../../common/type';
|
||||||
import { DatePicker } from 'antd';
|
import { Button, DatePicker } from 'antd';
|
||||||
import { CheckCircleFilled } from '@ant-design/icons';
|
import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
||||||
import Loading from './Loading';
|
import Loading from './Loading';
|
||||||
import FilterItem from './FilterItem';
|
import FilterItem from './FilterItem';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -21,10 +21,13 @@ type Props = {
|
|||||||
dateInfo: DateInfoType;
|
dateInfo: DateInfoType;
|
||||||
entityInfo: EntityInfoType;
|
entityInfo: EntityInfoType;
|
||||||
integrateSystem?: string;
|
integrateSystem?: string;
|
||||||
|
parseTimeCost?: number;
|
||||||
|
isDeveloper?: boolean;
|
||||||
onSelectParseInfo: (parseInfo: ChatContextType) => void;
|
onSelectParseInfo: (parseInfo: ChatContextType) => void;
|
||||||
onSwitchEntity: (entityId: string) => void;
|
onSwitchEntity: (entityId: string) => void;
|
||||||
onFiltersChange: (filters: FilterItemType[]) => void;
|
onFiltersChange: (filters: FilterItemType[]) => void;
|
||||||
onDateInfoChange: (dateRange: any) => void;
|
onDateInfoChange: (dateRange: any) => void;
|
||||||
|
onRefresh: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_OPTION_VALUES_COUNT = 2;
|
const MAX_OPTION_VALUES_COUNT = 2;
|
||||||
@@ -39,10 +42,13 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
dateInfo,
|
dateInfo,
|
||||||
entityInfo,
|
entityInfo,
|
||||||
integrateSystem,
|
integrateSystem,
|
||||||
|
parseTimeCost,
|
||||||
|
isDeveloper,
|
||||||
onSelectParseInfo,
|
onSelectParseInfo,
|
||||||
onSwitchEntity,
|
onSwitchEntity,
|
||||||
onFiltersChange,
|
onFiltersChange,
|
||||||
onDateInfoChange,
|
onDateInfoChange,
|
||||||
|
onRefresh,
|
||||||
}) => {
|
}) => {
|
||||||
const prefixCls = `${PREFIX_CLS}-item`;
|
const prefixCls = `${PREFIX_CLS}-item`;
|
||||||
|
|
||||||
@@ -66,7 +72,15 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parseTip) {
|
if (parseTip) {
|
||||||
return getNode('意图解析失败', parseTip);
|
return getNode(
|
||||||
|
<>
|
||||||
|
意图解析失败
|
||||||
|
{parseTimeCost && isDeveloper && (
|
||||||
|
<span className={`${prefixCls}-title-tip`}>(耗时: {parseTimeCost}ms)</span>
|
||||||
|
)}
|
||||||
|
</>,
|
||||||
|
parseTip
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parseInfoOptions.length === 0) {
|
if (parseInfoOptions.length === 0) {
|
||||||
@@ -218,18 +232,19 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{filters?.map((filter: any) => (
|
{filters?.map((filter: any, index: number) => (
|
||||||
<FilterItem
|
<FilterItem
|
||||||
modelId={modelId!}
|
modelId={modelId!}
|
||||||
filters={dimensionFilters}
|
filters={dimensionFilters}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
|
index={index}
|
||||||
chatContext={currentParseInfo!}
|
chatContext={currentParseInfo!}
|
||||||
entityAlias={entityAlias}
|
entityAlias={entityAlias}
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
integrateSystem={integrateSystem}
|
integrateSystem={integrateSystem}
|
||||||
onFiltersChange={onFiltersChange}
|
onFiltersChange={onFiltersChange}
|
||||||
onSwitchEntity={onSwitchEntity}
|
onSwitchEntity={onSwitchEntity}
|
||||||
key={filter.name}
|
key={`${filter.name}_${index}`}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -238,23 +253,39 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
|
|
||||||
const getFiltersNode = () => {
|
const getFiltersNode = () => {
|
||||||
return (
|
return (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>筛选条件:</div>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-content`}>{getFilterContent(dimensionFilters)}</div>
|
<div className={`${prefixCls}-tip-item-name`}>筛选条件:</div>
|
||||||
</div>
|
<div className={`${prefixCls}-tip-item-content`}>
|
||||||
|
{getFilterContent(dimensionFilters)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button className={`${prefixCls}-reload`} size="small" onClick={onRefresh}>
|
||||||
|
<ReloadOutlined />
|
||||||
|
重新查询
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { type: agentType } = properties || {};
|
||||||
|
|
||||||
const tipNode = (
|
const tipNode = (
|
||||||
<div className={`${prefixCls}-tip`}>
|
<div className={`${prefixCls}-tip`}>
|
||||||
{getTipNode()}
|
{getTipNode()}
|
||||||
{getFiltersNode()}
|
{!(!!agentType && queryMode !== 'LLM_S2QL') && getFiltersNode()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return getNode(
|
return getNode(
|
||||||
<div className={`${prefixCls}-title-bar`}>
|
<div className={`${prefixCls}-title-bar`}>
|
||||||
<div>意图解析{parseInfoOptions?.length > 1 ? ':' : ''}</div>
|
<div>
|
||||||
|
意图解析
|
||||||
|
{parseTimeCost && isDeveloper && (
|
||||||
|
<span className={`${prefixCls}-title-tip`}>(耗时: {parseTimeCost}ms)</span>
|
||||||
|
)}
|
||||||
|
{parseInfoOptions?.length > 1 ? ':' : ''}
|
||||||
|
</div>
|
||||||
{parseInfoOptions?.length > 1 && (
|
{parseInfoOptions?.length > 1 && (
|
||||||
<div className={`${prefixCls}-content-options`}>
|
<div className={`${prefixCls}-content-options`}>
|
||||||
{parseInfoOptions.map((parseInfo, index) => (
|
{parseInfoOptions.map((parseInfo, index) => (
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import { SqlInfoType } from '../../common/type';
|
|||||||
type Props = {
|
type Props = {
|
||||||
integrateSystem?: string;
|
integrateSystem?: string;
|
||||||
sqlInfo: SqlInfoType;
|
sqlInfo: SqlInfoType;
|
||||||
|
sqlTimeCost?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo, sqlTimeCost }) => {
|
||||||
const [sqlType, setSqlType] = useState('');
|
const [sqlType, setSqlType] = useState('');
|
||||||
|
|
||||||
const tipPrefixCls = `${PREFIX_CLS}-item`;
|
const tipPrefixCls = `${PREFIX_CLS}-item`;
|
||||||
@@ -36,7 +37,11 @@ const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
|||||||
<div className={`${tipPrefixCls}-title-bar`}>
|
<div className={`${tipPrefixCls}-title-bar`}>
|
||||||
<CheckCircleFilled className={`${tipPrefixCls}-step-icon`} />
|
<CheckCircleFilled className={`${tipPrefixCls}-step-icon`} />
|
||||||
<div className={`${tipPrefixCls}-step-title`}>
|
<div className={`${tipPrefixCls}-step-title`}>
|
||||||
SQL生成:
|
SQL生成
|
||||||
|
{sqlTimeCost && (
|
||||||
|
<span className={`${tipPrefixCls}-title-tip`}>(耗时: {sqlTimeCost}ms)</span>
|
||||||
|
)}
|
||||||
|
:
|
||||||
{sqlType && (
|
{sqlType && (
|
||||||
<span className={`${prefixCls}-toggle-expand-btn`} onClick={onCollapse}>
|
<span className={`${prefixCls}-toggle-expand-btn`} onClick={onCollapse}>
|
||||||
<UpOutlined />
|
<UpOutlined />
|
||||||
@@ -53,7 +58,7 @@ const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
|||||||
setSqlType(sqlType === 's2QL' ? '' : 's2QL');
|
setSqlType(sqlType === 's2QL' ? '' : 's2QL');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
S2QL
|
解析S2QL
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{sqlInfo.logicSql && (
|
{sqlInfo.logicSql && (
|
||||||
@@ -65,7 +70,7 @@ const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
|||||||
setSqlType(sqlType === 'logicSql' ? '' : 'logicSql');
|
setSqlType(sqlType === 'logicSql' ? '' : 'logicSql');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
逻辑SQL
|
修正S2QL
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{sqlInfo.querySql && (
|
{sqlInfo.querySql && (
|
||||||
@@ -77,7 +82,7 @@ const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
|||||||
setSqlType(sqlType === 'querySql' ? '' : 'querySql');
|
setSqlType(sqlType === 'querySql' ? '' : 'querySql');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
物理SQL
|
执行SQL
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -91,7 +96,7 @@ const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
|||||||
: ''
|
: ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{sqlType && (
|
{sqlType && sqlInfo[sqlType] && (
|
||||||
<>
|
<>
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
className={`${prefixCls}-code`}
|
className={`${prefixCls}-code`}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
FilterItemType,
|
FilterItemType,
|
||||||
MsgDataType,
|
MsgDataType,
|
||||||
ParseStateEnum,
|
ParseStateEnum,
|
||||||
|
ParseTimeCostType,
|
||||||
SimilarQuestionType,
|
SimilarQuestionType,
|
||||||
} from '../../common/type';
|
} from '../../common/type';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -27,8 +28,8 @@ type Props = {
|
|||||||
agentId?: number;
|
agentId?: number;
|
||||||
score?: number;
|
score?: number;
|
||||||
filter?: any[];
|
filter?: any[];
|
||||||
isLastMessage?: boolean;
|
|
||||||
parseInfos?: ChatContextType[];
|
parseInfos?: ChatContextType[];
|
||||||
|
parseTimeCostValue?: ParseTimeCostType;
|
||||||
msgData?: MsgDataType;
|
msgData?: MsgDataType;
|
||||||
triggerResize?: boolean;
|
triggerResize?: boolean;
|
||||||
isDeveloper?: boolean;
|
isDeveloper?: boolean;
|
||||||
@@ -47,9 +48,9 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
agentId,
|
agentId,
|
||||||
score,
|
score,
|
||||||
filter,
|
filter,
|
||||||
isLastMessage,
|
|
||||||
triggerResize,
|
triggerResize,
|
||||||
parseInfos,
|
parseInfos,
|
||||||
|
parseTimeCostValue,
|
||||||
msgData,
|
msgData,
|
||||||
isDeveloper,
|
isDeveloper,
|
||||||
integrateSystem,
|
integrateSystem,
|
||||||
@@ -61,6 +62,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [data, setData] = useState<MsgDataType>();
|
const [data, setData] = useState<MsgDataType>();
|
||||||
const [parseLoading, setParseLoading] = useState(false);
|
const [parseLoading, setParseLoading] = useState(false);
|
||||||
|
const [parseTimeCost, setParseTimeCost] = useState<ParseTimeCostType>();
|
||||||
const [parseInfo, setParseInfo] = useState<ChatContextType>();
|
const [parseInfo, setParseInfo] = useState<ChatContextType>();
|
||||||
const [parseInfoOptions, setParseInfoOptions] = useState<ChatContextType[]>([]);
|
const [parseInfoOptions, setParseInfoOptions] = useState<ChatContextType[]>([]);
|
||||||
const [parseTip, setParseTip] = useState('');
|
const [parseTip, setParseTip] = useState('');
|
||||||
@@ -97,24 +99,50 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onExecute = async (parseInfoValue: ChatContextType) => {
|
const onExecute = async (
|
||||||
|
parseInfoValue: ChatContextType,
|
||||||
|
parseInfos?: ChatContextType[],
|
||||||
|
isSwitchParseInfo?: boolean
|
||||||
|
) => {
|
||||||
setExecuteMode(true);
|
setExecuteMode(true);
|
||||||
setExecuteLoading(true);
|
if (isSwitchParseInfo) {
|
||||||
|
setEntitySwitchLoading(true);
|
||||||
|
} else {
|
||||||
|
setExecuteLoading(true);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const res: any = await chatExecute(msg, conversationId!, parseInfoValue);
|
const res: any = await chatExecute(msg, conversationId!, parseInfoValue);
|
||||||
setExecuteLoading(false);
|
|
||||||
const valid = updateData(res);
|
const valid = updateData(res);
|
||||||
onMsgDataLoaded?.(
|
onMsgDataLoaded?.(
|
||||||
{
|
{
|
||||||
...res.data,
|
...res.data,
|
||||||
chatContext: parseInfoValue,
|
parseInfos,
|
||||||
|
queryId: parseInfoValue.queryId,
|
||||||
},
|
},
|
||||||
valid
|
valid
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setExecuteLoading(false);
|
|
||||||
setExecuteTip(SEARCH_EXCEPTION_TIP);
|
setExecuteTip(SEARCH_EXCEPTION_TIP);
|
||||||
}
|
}
|
||||||
|
if (isSwitchParseInfo) {
|
||||||
|
setEntitySwitchLoading(false);
|
||||||
|
} else {
|
||||||
|
setExecuteLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateDimensionFitlers = (filters: FilterItemType[]) => {
|
||||||
|
setDimensionFilters(
|
||||||
|
filters.sort((a, b) => {
|
||||||
|
if (a.name < b.name) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.name > b.name) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendMsg = async () => {
|
const sendMsg = async () => {
|
||||||
@@ -122,7 +150,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
const parseData: any = await chatParse(msg, conversationId, modelId, agentId, filter);
|
const parseData: any = await chatParse(msg, conversationId, modelId, agentId, filter);
|
||||||
setParseLoading(false);
|
setParseLoading(false);
|
||||||
const { code, data } = parseData || {};
|
const { code, data } = parseData || {};
|
||||||
const { state, selectedParses, candidateParses, queryId } = data || {};
|
const { state, selectedParses, candidateParses, queryId, parseTimeCost } = data || {};
|
||||||
if (
|
if (
|
||||||
code !== 200 ||
|
code !== 200 ||
|
||||||
state === ParseStateEnum.FAILED ||
|
state === ParseStateEnum.FAILED ||
|
||||||
@@ -143,10 +171,11 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
setParseInfoOptions(parseInfos || []);
|
setParseInfoOptions(parseInfos || []);
|
||||||
const parseInfoValue = parseInfos[0];
|
const parseInfoValue = parseInfos[0];
|
||||||
setParseInfo(parseInfoValue);
|
setParseInfo(parseInfoValue);
|
||||||
|
setParseTimeCost(parseTimeCost);
|
||||||
setEntityInfo(parseInfoValue.entityInfo || {});
|
setEntityInfo(parseInfoValue.entityInfo || {});
|
||||||
setDimensionFilters(parseInfoValue?.dimensionFilters || []);
|
updateDimensionFitlers(parseInfoValue?.dimensionFilters || []);
|
||||||
setDateInfo(parseInfoValue?.dateInfo);
|
setDateInfo(parseInfoValue?.dateInfo);
|
||||||
onExecute(parseInfoValue);
|
onExecute(parseInfoValue, parseInfos);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -161,7 +190,8 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
const parseInfoValue = parseInfoOptionsValue[0];
|
const parseInfoValue = parseInfoOptionsValue[0];
|
||||||
setParseInfoOptions(parseInfoOptionsValue);
|
setParseInfoOptions(parseInfoOptionsValue);
|
||||||
setParseInfo(parseInfoValue);
|
setParseInfo(parseInfoValue);
|
||||||
setDimensionFilters(parseInfoValue.dimensionFilters || []);
|
setParseTimeCost(parseTimeCostValue);
|
||||||
|
updateDimensionFitlers(parseInfoValue.dimensionFilters || []);
|
||||||
setDateInfo(parseInfoValue.dateInfo);
|
setDateInfo(parseInfoValue.dateInfo);
|
||||||
setExecuteMode(true);
|
setExecuteMode(true);
|
||||||
updateData({ code: 200, data: msgData, msg: 'success' });
|
updateData({ code: 200, data: msgData, msg: 'success' });
|
||||||
@@ -179,7 +209,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
const chatContextValue = { ...(chatContext || {}), queryId: parseInfo?.queryId };
|
const chatContextValue = { ...(chatContext || {}), queryId: parseInfo?.queryId };
|
||||||
setParseInfo(chatContextValue);
|
setParseInfo(chatContextValue);
|
||||||
setEntityInfo(entityInfo);
|
setEntityInfo(entityInfo);
|
||||||
setDimensionFilters(chatContextValue?.dimensionFilters || []);
|
updateDimensionFitlers(chatContextValue?.dimensionFilters || []);
|
||||||
setDateInfo(chatContextValue?.dateInfo);
|
setDateInfo(chatContextValue?.dateInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -213,7 +243,12 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const resChatContext = res.data?.chatContext;
|
const resChatContext = res.data?.chatContext;
|
||||||
const contextValue = { ...(resChatContext || chatContextValue), queryId };
|
const contextValue = { ...(resChatContext || chatContextValue), queryId };
|
||||||
const dataValue = { ...res.data, chatContext: contextValue };
|
const dataValue = {
|
||||||
|
...res.data,
|
||||||
|
chatContext: contextValue,
|
||||||
|
parseInfos: parseInfoOptions,
|
||||||
|
queryId,
|
||||||
|
};
|
||||||
onMsgDataLoaded?.(dataValue, true, true);
|
onMsgDataLoaded?.(dataValue, true, true);
|
||||||
setData(dataValue);
|
setData(dataValue);
|
||||||
setParseInfo(contextValue);
|
setParseInfo(contextValue);
|
||||||
@@ -227,13 +262,14 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
|
|
||||||
const onSelectParseInfo = async (parseInfoValue: ChatContextType) => {
|
const onSelectParseInfo = async (parseInfoValue: ChatContextType) => {
|
||||||
setParseInfo(parseInfoValue);
|
setParseInfo(parseInfoValue);
|
||||||
setDimensionFilters(parseInfoValue.dimensionFilters || []);
|
updateDimensionFitlers(parseInfoValue.dimensionFilters || []);
|
||||||
setDateInfo(parseInfoValue.dateInfo);
|
setDateInfo(parseInfoValue.dateInfo);
|
||||||
if (parseInfoValue.entityInfo) {
|
if (parseInfoValue.entityInfo) {
|
||||||
setEntityInfo(parseInfoValue.entityInfo);
|
setEntityInfo(parseInfoValue.entityInfo);
|
||||||
} else {
|
} else {
|
||||||
getEntityInfo(parseInfoValue);
|
getEntityInfo(parseInfoValue);
|
||||||
}
|
}
|
||||||
|
onExecute(parseInfoValue, parseInfoOptions, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelectQuestion = (question: SimilarQuestionType) => {
|
const onSelectQuestion = (question: SimilarQuestionType) => {
|
||||||
@@ -261,15 +297,22 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
dateInfo={dateInfo}
|
dateInfo={dateInfo}
|
||||||
entityInfo={entityInfo}
|
entityInfo={entityInfo}
|
||||||
integrateSystem={integrateSystem}
|
integrateSystem={integrateSystem}
|
||||||
|
parseTimeCost={parseTimeCost?.parseTime}
|
||||||
|
isDeveloper={isDeveloper}
|
||||||
onSelectParseInfo={onSelectParseInfo}
|
onSelectParseInfo={onSelectParseInfo}
|
||||||
onSwitchEntity={onSwitchEntity}
|
onSwitchEntity={onSwitchEntity}
|
||||||
onFiltersChange={onFiltersChange}
|
onFiltersChange={onFiltersChange}
|
||||||
onDateInfoChange={onDateInfoChange}
|
onDateInfoChange={onDateInfoChange}
|
||||||
|
onRefresh={onRefresh}
|
||||||
/>
|
/>
|
||||||
{executeMode && (
|
{executeMode && (
|
||||||
<>
|
<>
|
||||||
{!isMobile && parseInfo?.sqlInfo && isDeveloper && integrateSystem !== 'c2' && (
|
{!isMobile && parseInfo?.sqlInfo && isDeveloper && integrateSystem !== 'c2' && (
|
||||||
<SqlItem integrateSystem={integrateSystem} sqlInfo={parseInfo.sqlInfo} />
|
<SqlItem
|
||||||
|
integrateSystem={integrateSystem}
|
||||||
|
sqlInfo={parseInfo.sqlInfo}
|
||||||
|
sqlTimeCost={parseTimeCost?.sqlTime}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<ExecuteItem
|
<ExecuteItem
|
||||||
queryId={parseInfo?.queryId}
|
queryId={parseInfo?.queryId}
|
||||||
@@ -280,8 +323,8 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
data={data}
|
data={data}
|
||||||
triggerResize={triggerResize}
|
triggerResize={triggerResize}
|
||||||
executeItemNode={executeItemNode}
|
executeItemNode={executeItemNode}
|
||||||
|
isDeveloper={isDeveloper}
|
||||||
renderCustomExecuteNode={renderCustomExecuteNode}
|
renderCustomExecuteNode={renderCustomExecuteNode}
|
||||||
onRefresh={onRefresh}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -294,11 +337,9 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{(parseTip !== '' || (executeMode && !executeLoading)) &&
|
{(parseTip !== '' || (executeMode && !executeLoading)) && integrateSystem !== 'c2' && (
|
||||||
integrateSystem !== 'c2' &&
|
<Tools queryId={parseInfo?.queryId || 0} scoreValue={score} />
|
||||||
integrateSystem !== 'showcase' && (
|
)}
|
||||||
<Tools queryId={parseInfo?.queryId || 0} scoreValue={score} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -133,6 +133,12 @@
|
|||||||
column-gap: 10px;
|
column-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-title-tip {
|
||||||
|
margin-left: 2px;
|
||||||
|
color: var(--text-color-third);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
&-step-title {
|
&-step-title {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
@@ -140,6 +146,7 @@
|
|||||||
|
|
||||||
&-reload {
|
&-reload {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
|
width: fit-content;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: var(--text-color-secondary);
|
color: var(--text-color-secondary);
|
||||||
font-size: 13px !important;
|
font-size: 13px !important;
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ const BarChart: React.FC<Props> = ({ data, triggerResize, loading, onApplyAuth }
|
|||||||
const data = (queryResults || []).sort(
|
const data = (queryResults || []).sort(
|
||||||
(a: any, b: any) => b[metricColumnName] - a[metricColumnName]
|
(a: any, b: any) => b[metricColumnName] - a[metricColumnName]
|
||||||
);
|
);
|
||||||
const xData = data.map(item => item[categoryColumnName]);
|
const xData = data.map(item =>
|
||||||
|
item[categoryColumnName] !== undefined ? item[categoryColumnName] : '未知'
|
||||||
|
);
|
||||||
instanceObj.setOption({
|
instanceObj.setOption({
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ const MetricCard: React.FC<Props> = ({ data, loading, onApplyAuth }) => {
|
|||||||
) : (
|
) : (
|
||||||
<div style={{ display: 'flex', alignItems: 'flex-end' }}>
|
<div style={{ display: 'flex', alignItems: 'flex-end' }}>
|
||||||
<div className={`${prefixCls}-indicator-value`}>
|
<div className={`${prefixCls}-indicator-value`}>
|
||||||
{dataFormatType === 'percent' || dataFormatType === 'decimal'
|
{typeof value === 'string' && isNaN(+value)
|
||||||
|
? value
|
||||||
|
: dataFormatType === 'percent' || dataFormatType === 'decimal'
|
||||||
? `${formatByDecimalPlaces(
|
? `${formatByDecimalPlaces(
|
||||||
dataFormat?.needMultiply100 ? +value * 100 : value,
|
dataFormat?.needMultiply100 ? +value * 100 : value,
|
||||||
dataFormat?.decimalPlaces || 2
|
dataFormat?.decimalPlaces || 2
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { formatByDecimalPlaces, getFormattedValue } from '../../../utils/utils';
|
import { formatByDecimalPlaces, getFormattedValue, isMobile } from '../../../utils/utils';
|
||||||
import { Table as AntTable } from 'antd';
|
import { Table as AntTable } from 'antd';
|
||||||
import { MsgDataType } from '../../../common/type';
|
import { MsgDataType } from '../../../common/type';
|
||||||
import { CLS_PREFIX } from '../../../common/constants';
|
import { CLS_PREFIX } from '../../../common/constants';
|
||||||
@@ -70,7 +70,13 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
|
|||||||
<div className={prefixCls}>
|
<div className={prefixCls}>
|
||||||
<AntTable
|
<AntTable
|
||||||
pagination={
|
pagination={
|
||||||
queryResults.length <= 10 ? false : { defaultPageSize: 10, position: ['bottomCenter'] }
|
queryResults.length <= 10
|
||||||
|
? false
|
||||||
|
: {
|
||||||
|
defaultPageSize: 10,
|
||||||
|
position: ['bottomCenter'],
|
||||||
|
size: isMobile ? 'small' : 'default',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { PREFIX_CLS } from '../../common/constants';
|
|||||||
import Text from './Text';
|
import Text from './Text';
|
||||||
import DrillDownDimensions from '../DrillDownDimensions';
|
import DrillDownDimensions from '../DrillDownDimensions';
|
||||||
import MetricOptions from '../MetricOptions';
|
import MetricOptions from '../MetricOptions';
|
||||||
|
import { isMobile } from '../../utils/utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
queryId?: number;
|
queryId?: number;
|
||||||
@@ -115,7 +116,11 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (categoryField?.length > 0 && metricFields?.length > 0) {
|
if (
|
||||||
|
categoryField?.length > 0 &&
|
||||||
|
metricFields?.length > 0 &&
|
||||||
|
(isMobile ? dataSource?.length <= 20 : dataSource?.length <= 50)
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<Bar
|
<Bar
|
||||||
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createFromIconfontCN } from '@ant-design/icons';
|
import { createFromIconfontCN } from '@ant-design/icons';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_4120566_2vn019wsui6.js',
|
scriptUrl: '//at.alicdn.com/t/c/font_4120566_x6akuij1kod.js',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ const Chat = () => {
|
|||||||
agentId={5}
|
agentId={5}
|
||||||
conversationId={112211121}
|
conversationId={112211121}
|
||||||
onMsgDataLoaded={onMsgDataLoaded}
|
onMsgDataLoaded={onMsgDataLoaded}
|
||||||
isLastMessage
|
|
||||||
triggerResize={triggerResize}
|
triggerResize={triggerResize}
|
||||||
integrateSystem="wiki"
|
integrateSystem="wiki"
|
||||||
isDeveloper
|
isDeveloper
|
||||||
|
|||||||
21
webapp/pnpm-lock.yaml
generated
21
webapp/pnpm-lock.yaml
generated
@@ -319,8 +319,8 @@ importers:
|
|||||||
specifier: ^4.8.14
|
specifier: ^4.8.14
|
||||||
version: 4.8.22
|
version: 4.8.22
|
||||||
'@antv/g6-core':
|
'@antv/g6-core':
|
||||||
specifier: ^0.8.21
|
specifier: ^0.8.23
|
||||||
version: 0.8.22
|
version: 0.8.23
|
||||||
'@antv/layout':
|
'@antv/layout':
|
||||||
specifier: ^0.3.20
|
specifier: ^0.3.20
|
||||||
version: 0.3.23(dagre@0.8.5)
|
version: 0.3.23(dagre@0.8.5)
|
||||||
@@ -1514,6 +1514,21 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@antv/g6-core@0.8.23:
|
||||||
|
resolution: {integrity: sha512-JWdnba5Bx4/hLhbIQeyvdgh68SDYZisveukuBifxLKODCNJNKTopmWf1w6tU+RxAT2k5ByXkTGWQE1IkIL8O+Q==}
|
||||||
|
dependencies:
|
||||||
|
'@antv/algorithm': 0.1.26
|
||||||
|
'@antv/dom-util': 2.0.4
|
||||||
|
'@antv/event-emitter': 0.1.3
|
||||||
|
'@antv/g-base': 0.5.15
|
||||||
|
'@antv/g-math': 0.1.9
|
||||||
|
'@antv/matrix-util': 3.1.0-beta.3
|
||||||
|
'@antv/path-util': 2.0.15
|
||||||
|
'@antv/util': 2.0.17
|
||||||
|
ml-matrix: 6.10.4
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@antv/g6-element@0.8.22:
|
/@antv/g6-element@0.8.22:
|
||||||
resolution: {integrity: sha512-rTJgaFDeaiHEF5d+hdJEGbh+Z272bi+Zzu5aTDWCtFFgxtosdeOQGWdyhIEeLCstRvlP3RaaztBIsSZm5BWFsA==}
|
resolution: {integrity: sha512-rTJgaFDeaiHEF5d+hdJEGbh+Z272bi+Zzu5aTDWCtFFgxtosdeOQGWdyhIEeLCstRvlP3RaaztBIsSZm5BWFsA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1533,7 +1548,7 @@ packages:
|
|||||||
'@antv/g-canvas': 0.5.14
|
'@antv/g-canvas': 0.5.14
|
||||||
'@antv/g-math': 0.1.9
|
'@antv/g-math': 0.1.9
|
||||||
'@antv/g-svg': 0.5.7
|
'@antv/g-svg': 0.5.7
|
||||||
'@antv/g6-core': 0.8.22
|
'@antv/g6-core': 0.8.23
|
||||||
'@antv/g6-element': 0.8.22
|
'@antv/g6-element': 0.8.22
|
||||||
'@antv/g6-plugin': 0.8.22
|
'@antv/g6-plugin': 0.8.22
|
||||||
'@antv/hierarchy': 0.6.11
|
'@antv/hierarchy': 0.6.11
|
||||||
|
|||||||
Reference in New Issue
Block a user