From 3b09a5c0edd98b67361c9a05c2c776c3f7e23f03 Mon Sep 17 00:00:00 2001 From: tristanliu <37809633+sevenliu1896@users.noreply.github.com> Date: Thu, 30 May 2024 11:26:37 +0800 Subject: [PATCH] [improvement][headless-fe] Added a simplified mode to the question-answering system. (#1051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [improvement][semantic-fe] Add model alias setting & Add view permission restrictions to the model permission management tab. [improvement][semantic-fe] Add permission control to the action buttons for the main domain; apply high sensitivity filtering to the authorization of metrics/dimensions. [improvement][semantic-fe] Optimize the editing mode in the dimension/metric/datasource components to use the modelId stored in the database for data, instead of relying on the data from the state manager. * [improvement][semantic-fe] Add time granularity setting in the data source configuration. * [improvement][semantic-fe] Dictionary import for dimension values supported in Q&A visibility * [improvement][semantic-fe] Modification of data source creation prompt wording" * [improvement][semantic-fe] metric market experience optimization * [improvement][semantic-fe] enhance the analysis of metric trends * [improvement][semantic-fe] optimize the presentation of metric trend permissions * [improvement][semantic-fe] add metric trend download functionality * [improvement][semantic-fe] fix the dimension initialization issue in metric correlation * [improvement][semantic-fe] Fix the issue of database changes not taking effect when creating based on an SQL data source. * [improvement][semantic-fe] Optimizing pagination logic and some CSS styles * [improvement][semantic-fe] Fixing the API for the indicator list by changing "current" to "pageNum" * [improvement][semantic-fe] Fixing the default value setting for the indicator list * [improvement][semantic-fe] Adding batch operations for indicators/dimensions/models * [improvement][semantic-fe] Replacing the single status update API for indicators/dimensions with a batch update API * [improvement][semantic-fe] Redesigning the indicator homepage to incorporate trend charts and table functionality for indicators * [improvement][semantic-fe] Optimizing the logic for setting dimension values and editing data sources, and adding system settings functionality * [improvement][semantic-fe] Upgrading antd version to 5.x, extracting the batch operation button component, optimizing the interaction for system settings, and expanding the configuration generation types for list-to-select component. * [improvement][semantic-fe] Adding the ability to filter dimensions based on whether they are tags or not. * [improvement][semantic-fe] Adding the ability to edit relationships between models in the canvas. * [improvement][semantic-fe] Updating the datePicker component to use dayjs instead. * [improvement][semantic-fe] Fixing the issue with passing the model ID for dimensions in the indicator market. * [improvement][semantic-fe] Fixing the abnormal state of the popup when creating a model. * [improvement][semantic-fe] Adding permission logic for bulk operations in the indicator market. * [improvement][semantic-fe] Adding the ability to download and transpose data. * [improvement][semantic-fe] Fixing the initialization issue with the date selection component in the indicator details page when switching time granularity. * [improvement][semantic-fe] Fixing the logic error in the dimension value setting. * [improvement][semantic-fe] Fixing the synchronization issue with the question and answer settings information. * [improvement][semantic-fe] Optimizing the canvas functionality for better performance and user experience. * [improvement][semantic-fe] Optimizing the update process for drawing model relationship edges in the canvas. * [improvement][semantic-fe] Changing the line type for canvas connections. * [improvement][semantic-fe] Replacing the initialization variable from "semantic" to "headless". * [improvement][semantic-fe] Fixing the missing migration issue for default drill-down dimension configuration in model editing. Additionally, optimizing the data retrieval method for initializing fields in the model. * [improvement][semantic-fe] Updating the logic for the fieldName. * [improvement][semantic-fe] Adjusting the position of the metrics tab. * [improvement][semantic-fe] Changing the 字段名称 to 英文名称. * [improvement][semantic-fe] Fix metric measurement deletion. * [improvement][semantic-fe] UI optimization for metric details page. * [improvement][semantic-fe] UI optimization for metric details page. * [improvement][semantic-fe] UI adjustment for metric details page. * [improvement][semantic-fe] The granularity field in the time type of model editing now supports setting it as empty. * [improvement][semantic-fe] Added field type and metric type to the metric creation options. * [improvement][semantic-fe] The organization structure selection feature has been added to the permission management. * [improvement][semantic-fe] Improved user experience for the metric list. * [improvement][semantic-fe] fix update the metric list. * [improvement][headless-fe] Added view management functionality. * [improvement][headless-fe] The view management functionality has been added. This feature allows users to create, edit, and manage different views within the system. * [improvement][headless-fe] Added model editing side effect detection. * [improvement][headless-fe] Fixed the logic error in view editing. * [improvement][headless-fe] Fixed the issue with initializing dimension associations in metric settings. * [improvement][headless-fe] Added the ability to hide the Q&A settings entry point. * [improvement][headless-fe] Fixed the issue with selecting search results in metric field creation. * [improvement][headless-fe] Added search functionality to the field list in model editing. * [improvement][headless-fe] fix the field list in model editing * [improvement][headless-fe] Restructured the data for the dimension value settings interface. * [improvement][headless-fe] Added dynamic variable functionality to model creation based on SQL scripts. * [improvement][headless-fe] Added support for passing dynamic variables as parameters in the executeSql function. * [improvement][headless-fe] Resolved the issue where users were unable to select all options for dimensions, metrics, and fields in the metric generation process. * [improvement][headless-fe] Replaced the term "view" with "dataset" * [improvement][headless-fe] Added the ability to export metrics and dimensions to a specific target. * [improvement][headless-fe] Enhanced dataset creation to support the tag mode. * [improvement][headless-fe] Added tag value setting. * [improvement][headless-fe] Optimized the tag setting system. * [improvement][headless-fe] Optimized the tag setting system. * [improvement][headless-fe] Updated the data initialization for model editing to use API requests instead. * [improvement][headless-fe] Added search functionality to model management. * [improvement][headless-fe] Removed field null validation during model editing. * [improvement][headless-fe] Updated the batch operation button component. * [improvement][headless-fe] Optimized the logic for initializing indicators in dimension value settings. * [improvement][headless-fe] Adjusted the length of the input field for model editing names. * [improvement][headless-fe] Lock the version of the @ant-design/pro-table component and replace it with @ant-design/pro-components. * [improvement][headless-fe] Optimized the style of the metrics market and tags market. * [improvement][headless-fe] The quick creation of model fields now defaults to using the "comment" field for filling. * [improvement][headless-fe] The quick creation of model fields now defaults to using the "comment" field for filling * [improvement][headless-fe] The quick creation of model fields now defaults to using the "comment" field for filling. * [improvement][headless-fe] Fixed the issue where the conditions for metric measurement creation were not being saved correctly. * [improvement][headless-fe] Default value setting for hiding dimensions. * [improvement][headless-fe] Updated the file imports in the project. * [improvement][headless-fe] Adjusted the logic for displaying the tab in the theme domain. * [improvement][headless-fe] Added term management functionality. * [improvement][headless-fe] When creating a model, the current metric operator now allows for clearance. * [improvement][headless-fe] Term management interface transformation * [improvement][headless-fe] Migrating scaffold version to @umi/max * [improvement][headless-fe] remove modle column * [improvement][headless-fe] 1.Added configuration for the large language model in the agent; 2.upgraded React version from 17 to 18; 3.modified some UI effects. * [improvement][headless-fe] Added a simplified mode to the question-answering system. --- webapp/packages/chat-sdk/package.json | 8 +- .../src/Chat/MessageContainer/index.tsx | 8 +- webapp/packages/chat-sdk/src/Chat/index.tsx | 28 +- .../chat-sdk/src/Chat/style.module.less | 4 +- .../packages/chat-sdk/src/common/constants.ts | 35 ++- webapp/packages/chat-sdk/src/common/type.ts | 4 +- .../src/components/ChatItem/ExecuteItem.tsx | 42 ++- .../src/components/ChatItem/FilterItem.tsx | 2 +- .../src/components/ChatItem/ParseTip.tsx | 13 +- .../src/components/ChatItem/SqlItem.tsx | 14 + .../src/components/ChatItem/index.tsx | 46 ++-- .../src/components/ChatMsg/MarkDown/index.tsx | 31 +++ .../components/ChatMsg/MarkDown/style.less | 9 + .../src/components/ChatMsg/Table/index.tsx | 12 +- .../chat-sdk/src/components/ChatMsg/index.tsx | 244 +++++++++++------- 15 files changed, 358 insertions(+), 142 deletions(-) create mode 100644 webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/index.tsx create mode 100644 webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/style.less diff --git a/webapp/packages/chat-sdk/package.json b/webapp/packages/chat-sdk/package.json index beeb24b95..0e9780605 100644 --- a/webapp/packages/chat-sdk/package.json +++ b/webapp/packages/chat-sdk/package.json @@ -9,16 +9,22 @@ "@ant-design/icons": "^4.7.0", "@uiw/react-watermark": "^0.0.5", "ahooks": "^3.7.8", - "antd": "^5.11.2", + "antd": "^5.17.4", "axios": "^0.21.1", "classnames": "^2.3.2", "dayjs": "^1.11.10", "echarts": "^5.4.2", + "github-markdown-css": "^5.5.1", + "highlight.js": "^11.9.0", "lodash": "^4.17.11", "moment": "^2.29.4", "react-copy-to-clipboard": "^5.1.0", + "react-grid-layout": "^1.4.4", + "react-markdown": "^9.0.1", "react-spinners": "^0.13.8", "react-syntax-highlighter": "^15.5.0", + "rehype-highlight": "^7.0.0", + "remark-gfm": "^4.0.0", "sql-formatter": "^2.3.3", "tslib": "^2.5.2" }, diff --git a/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx b/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx index ba342ecaa..8e4084522 100644 --- a/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx +++ b/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx @@ -18,6 +18,7 @@ type Props = { chatVisible?: boolean; isDeveloper?: boolean; integrateSystem?: string; + isSimpleMode?: boolean; onMsgDataLoaded: ( data: MsgDataType, questionId: string | number, @@ -37,6 +38,7 @@ const MessageContainer: React.FC = ({ chatVisible, isDeveloper, integrateSystem, + isSimpleMode, onMsgDataLoaded, onSendMsg, }) => { @@ -65,7 +67,7 @@ const MessageContainer: React.FC = ({ return (
- {messageList.map((msgItem: MessageItem, index: number) => { + {messageList.map((msgItem: MessageItem) => { const { id: msgId, modelId, @@ -92,6 +94,7 @@ const MessageContainer: React.FC = ({ {identityMsg && } = ( const [agentListVisible, setAgentListVisible] = useState(true); const [showCaseVisible, setShowCaseVisible] = useState(false); + const [isSimpleMode, setIsSimpleMode] = useState(false); + const conversationRef = useRef(); const chatFooterRef = useRef(); @@ -370,12 +372,32 @@ const Chat: ForwardRefRenderFunction = (
{currentAgent && !isMobile && !noInput && (
-
{currentAgent.name}
-
{currentAgent.description}
+ + + +
{currentAgent.name}
+
{currentAgent.description}
+ + { + setIsSimpleMode(checked); + }} + /> + +
+ + +
)} = ({ @@ -31,8 +32,11 @@ const ExecuteItem: React.FC = ({ data, triggerResize, isDeveloper, + isSimpleMode, }) => { const prefixCls = `${PREFIX_CLS}-item`; + const [showMsgContentTable, setShowMsgContentTable] = useState(false); + const [msgContentType, setMsgContentType] = useState(); const getNodeTip = (title: ReactNode, tip?: string) => { return ( @@ -73,11 +77,28 @@ const ExecuteItem: React.FC = ({ <>
-
- 数据查询 - {data?.queryTimeCost && isDeveloper && ( - (耗时: {data.queryTimeCost}ms) - )} +
+ + + 数据查询 + {data?.queryTimeCost && isDeveloper && ( + (耗时: {data.queryTimeCost}ms) + )} + + + {[MsgContentTypeEnum.METRIC_TREND, MsgContentTypeEnum.METRIC_BAR].includes( + msgContentType as MsgContentTypeEnum + ) && ( + { + setShowMsgContentTable(checked); + }} + /> + )} + +
@@ -91,10 +112,15 @@ const ExecuteItem: React.FC = ({ ) : ( { + setMsgContentType(type); + }} /> )} diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx index 2ce62870f..b40c3c4da 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx @@ -126,7 +126,7 @@ const FilterItem: React.FC = ({ onFiltersChange(newFilters); }; - const onDateChange = (_: any, date: string) => { + const onDateChange = (_: any, date: string | string[]) => { const newFilters = filters.map((item, indexValue) => { if (item.bizName === filter.bizName && index === indexValue) { item.value = date; diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx index 3ac381029..4a3302448 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx @@ -5,6 +5,7 @@ import { Button, DatePicker } from 'antd'; import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons'; import Loading from './Loading'; import FilterItem from './FilterItem'; +import MarkDown from '../ChatMsg/MarkDown'; import classNames from 'classnames'; import { isMobile } from '../../utils/utils'; import dayjs from 'dayjs'; @@ -23,6 +24,7 @@ type Props = { integrateSystem?: string; parseTimeCost?: number; isDeveloper?: boolean; + isSimpleMode?: boolean; onSelectParseInfo: (parseInfo: ChatContextType) => void; onSwitchEntity: (entityId: string) => void; onFiltersChange: (filters: FilterItemType[]) => void; @@ -44,6 +46,7 @@ const ParseTip: React.FC = ({ integrateSystem, parseTimeCost, isDeveloper, + isSimpleMode, onSelectParseInfo, onSwitchEntity, onFiltersChange, @@ -51,7 +54,6 @@ const ParseTip: React.FC = ({ onRefresh, }) => { const prefixCls = `${PREFIX_CLS}-item`; - const getNode = (tipTitle: ReactNode, tipNode?: ReactNode) => { return (
@@ -99,6 +101,7 @@ const ParseTip: React.FC = ({ entity, elementMatches, nativeQuery, + textInfo = '', } = currentParseInfo || {}; const entityAlias = entity?.alias?.[0]?.split('.')?.[0]; @@ -152,15 +155,15 @@ const ParseTip: React.FC = ({
{dataSet?.name}
)} - {(queryType === 'METRIC' || queryType === 'METRIC_ID' || queryType === 'TAG') && ( + {(queryType === 'METRIC' || queryType === 'METRIC_TAG' || queryType === 'DETAIL') && (
查询模式:
- {queryType === 'METRIC' || queryType === 'METRIC_ID' ? '指标模式' : '标签模式'} + {queryType === 'METRIC' || queryType === 'METRIC_TAG' ? '指标模式' : '明细模式'}
)} - {queryType !== 'TAG' && + {queryType !== 'DETAIL' && metrics && metrics.length > 0 && !dimensions?.some(item => item.bizName?.includes('_id')) && ( @@ -315,7 +318,7 @@ const ParseTip: React.FC = ({
)}
, - tipNode + isSimpleMode ? : tipNode ); }; diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx index 19f133daa..8aa911055 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx @@ -162,6 +162,20 @@ const SqlItem: React.FC = ({
{priorExts}
)} + {schema?.terms?.length > 0 && ( +
+
术语:
+
+ {schema.terms + .map((item: any) => { + return `${item.name}${ + item.alias?.length > 0 ? `(${item.alias.join(',')})` : '' + }: ${item.description}`; + }) + .join('、')} +
+
+ )}
)} {sqlType === 'fewShots' && ( diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx index 5f96615b4..f3b19b938 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx @@ -36,6 +36,7 @@ type Props = { integrateSystem?: string; executeItemNode?: React.ReactNode; renderCustomExecuteNode?: boolean; + isSimpleMode?: boolean; onMsgDataLoaded?: (data: MsgDataType, valid: boolean, isRefresh?: boolean) => void; onUpdateMessageScroll?: () => void; onSendMsg?: (msg: string) => void; @@ -56,6 +57,7 @@ const ChatItem: React.FC = ({ integrateSystem, executeItemNode, renderCustomExecuteNode, + isSimpleMode, onMsgDataLoaded, onUpdateMessageScroll, onSendMsg, @@ -318,6 +320,7 @@ const ChatItem: React.FC = ({
= ({ /> {executeMode && ( <> - {!isMobile && parseInfo?.sqlInfo && isDeveloper && integrateSystem !== 'c2' && ( - - )} + {!isMobile && + parseInfo?.sqlInfo && + isDeveloper && + integrateSystem !== 'c2' && + !isSimpleMode && ( + + )} = ({ /> )} - {(parseTip !== '' || (executeMode && !executeLoading)) && integrateSystem !== 'c2' && ( - - )} + {(parseTip !== '' || (executeMode && !executeLoading)) && + integrateSystem !== 'c2' && + !isSimpleMode && ( + + )}
{(parseTip !== '' || (executeMode && !executeLoading)) && integrateSystem !== 'c2' && ( diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/index.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/index.tsx new file mode 100644 index 000000000..52549fe54 --- /dev/null +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/index.tsx @@ -0,0 +1,31 @@ +import { MsgDataType } from '../../../common/type'; +import { CLS_PREFIX } from '../../../common/constants'; +import { SizeType } from 'antd/es/config-provider/SizeContext'; +import rehypeHighlight from 'rehype-highlight'; +import remarkGfm from 'remark-gfm'; +import Markdown from 'react-markdown'; +import 'github-markdown-css/github-markdown.css'; +import 'highlight.js/styles/github.css'; + +type Props = { + // data: MsgDataType; + // size?: SizeType; + markdown: string; + loading?: boolean; + onApplyAuth?: (model: string) => void; +}; + +const MarkDown: React.FC = ({ markdown, loading, onApplyAuth }) => { + // const { textResult } = data; + const prefixCls = `${CLS_PREFIX}-markdown`; + + return ( +
+ + {markdown} + +
+ ); +}; + +export default MarkDown; diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/style.less b/webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/style.less new file mode 100644 index 000000000..11bf072b8 --- /dev/null +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MarkDown/style.less @@ -0,0 +1,9 @@ +@import '../../../styles/index.less'; + +@markdown-prefix-cls: ~'@{supersonic-chat-prefix}-markdown'; + +.@{markdown-prefix-cls} { + margin-top: 6px; + + +} \ No newline at end of file diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/Table/index.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/Table/index.tsx index b55fde1f7..63523832f 100644 --- a/webapp/packages/chat-sdk/src/components/ChatMsg/Table/index.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/Table/index.tsx @@ -33,10 +33,14 @@ const Table: React.FC = ({ data, size, loading, onApplyAuth }) => { if (dataFormatType === 'percent') { return (
- {`${formatByDecimalPlaces( - dataFormat?.needMultiply100 ? +value * 100 : value, - dataFormat?.decimalPlaces || 2 - )}%`} + {`${ + value + ? formatByDecimalPlaces( + dataFormat?.needMultiply100 ? +value * 100 : value, + dataFormat?.decimalPlaces || 2 + ) + : 0 + }%`}
); } diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/index.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/index.tsx index 54cb86a6f..247dfe58a 100644 --- a/webapp/packages/chat-sdk/src/components/ChatMsg/index.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/index.tsx @@ -1,12 +1,13 @@ import Bar from './Bar'; import MetricCard from './MetricCard'; import MetricTrend from './MetricTrend'; +import MarkDown from './MarkDown'; import Table from './Table'; import { ColumnType, DrillDownDimensionType, FieldType, MsgDataType } from '../../common/type'; import { useEffect, useState } from 'react'; import { queryData } from '../../service'; import classNames from 'classnames'; -import { PREFIX_CLS } from '../../common/constants'; +import { PREFIX_CLS, MsgContentTypeEnum } from '../../common/constants'; import Text from './Text'; import DrillDownDimensions from '../DrillDownDimensions'; import MetricOptions from '../MetricOptions'; @@ -17,13 +18,24 @@ type Props = { data: MsgDataType; chartIndex: number; triggerResize?: boolean; + forceShowTable?: boolean; + isSimpleMode?: boolean; + onMsgContentTypeChange?: (MsgContentTypeEnum) => void; }; -const ChatMsg: React.FC = ({ queryId, data, chartIndex, triggerResize }) => { +const ChatMsg: React.FC = ({ + queryId, + data, + chartIndex, + triggerResize, + forceShowTable = false, + isSimpleMode, + onMsgContentTypeChange, +}) => { const { queryColumns, queryResults, chatContext, queryMode } = data || {}; const { dimensionFilters, elementMatches } = chatContext || {}; - const [columns, setColumns] = useState(); + const [columns, setColumns] = useState([]); const [referenceColumn, setReferenceColumn] = useState(); const [dataSource, setDataSource] = useState(queryResults); const [drillDownDimension, setDrillDownDimension] = useState(); @@ -53,98 +65,137 @@ const ChatMsg: React.FC = ({ queryId, data, chartIndex, triggerResize }) setDrillDownDimension(undefined); setSecondDrillDownDimension(undefined); }, [data]); + const metricFields = columns.filter(item => item.showType === 'NUMBER'); + const getMsgContentType = () => { + const singleData = dataSource.length === 1; + const dateField = columns.find(item => item.showType === 'DATE' || item.type === 'DATE'); + const categoryField = columns.filter(item => item.showType === 'CATEGORY'); + const metricFields = columns.filter(item => item.showType === 'NUMBER'); + if (!columns) { + return; + } + if (isSimpleMode) { + return MsgContentTypeEnum.MARKDOWN; + } + if (forceShowTable) { + return MsgContentTypeEnum.TABLE; + } + const isDslMetricCard = + queryMode === 'LLM_S2SQL' && singleData && metricFields.length === 1 && columns.length === 1; + + const isMetricCard = (queryMode.includes('METRIC') || isDslMetricCard) && singleData; + + const isText = + columns.length === 1 && + columns[0].showType === 'CATEGORY' && + ((!queryMode.includes('METRIC') && !queryMode.includes('ENTITY')) || + queryMode === 'METRIC_INTERPRET') && + singleData; + if (isText) { + return MsgContentTypeEnum.TEXT; + } + + if (isMetricCard) { + return MsgContentTypeEnum.METRIC_CARD; + } + + const isTable = + !isText && + !isMetricCard && + (categoryField.length > 1 || + queryMode === 'TAG_DETAIL' || + queryMode === 'ENTITY_DIMENSION' || + (categoryField.length === 1 && metricFields.length === 0)); + + if (isTable) { + return MsgContentTypeEnum.TABLE; + } + const isMetricTrend = + dateField && + metricFields.length > 0 && + !dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn]); + + if (isMetricTrend) { + return MsgContentTypeEnum.METRIC_TREND; + } + + const isMetricBar = + categoryField?.length > 0 && + metricFields?.length > 0 && + (isMobile ? dataSource?.length <= 5 : dataSource?.length <= 50); + + if (isMetricBar) { + return MsgContentTypeEnum.METRIC_BAR; + } + return MsgContentTypeEnum.TABLE; + }; + + useEffect(() => { + const type = getMsgContentType(); + if (type) { + onMsgContentTypeChange?.(type); + } + }, [data, columns, isSimpleMode]); if (!queryColumns || !queryResults || !columns) { return null; } - const singleData = dataSource.length === 1; - const dateField = columns.find(item => item.showType === 'DATE' || item.type === 'DATE'); - const categoryField = columns.filter(item => item.showType === 'CATEGORY'); - const metricFields = columns.filter(item => item.showType === 'NUMBER'); - - const isDslMetricCard = - queryMode === 'LLM_S2SQL' && singleData && metricFields.length === 1 && columns.length === 1; - - const isMetricCard = (queryMode.includes('METRIC') || isDslMetricCard) && singleData; - - const isText = - columns.length === 1 && - columns[0].showType === 'CATEGORY' && - ((!queryMode.includes('METRIC') && !queryMode.includes('ENTITY')) || - queryMode === 'METRIC_INTERPRET') && - singleData; - - const isTable = - !isText && - !isMetricCard && - (categoryField.length > 1 || - queryMode === 'TAG_DETAIL' || - queryMode === 'ENTITY_DIMENSION' || - (categoryField.length === 1 && metricFields.length === 0)); - const getMsgContent = () => { - if (isText) { - return ; + const contentType = getMsgContentType(); + switch (contentType) { + case MsgContentTypeEnum.TEXT: + return ; + case MsgContentTypeEnum.METRIC_CARD: + return ( + + ); + case MsgContentTypeEnum.TABLE: + return ( + + ); + case MsgContentTypeEnum.METRIC_TREND: + return ( + + ); + case MsgContentTypeEnum.METRIC_BAR: + return ( + + ); + case MsgContentTypeEnum.MARKDOWN: + return ; + default: + return ( +
+ ); } - if (isMetricCard) { - return ( - - ); - } - if (isTable) { - return ( -
- ); - } - if ( - dateField && - metricFields.length > 0 && - !dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn]) - ) { - return ( - - ); - } - if ( - categoryField?.length > 0 && - metricFields?.length > 0 && - (isMobile ? dataSource?.length <= 5 : dataSource?.length <= 50) - ) { - return ( - - ); - } - return ( -
- ); }; const onLoadData = async (value: any) => { @@ -226,18 +277,25 @@ const ChatMsg: React.FC = ({ queryId, data, chartIndex, triggerResize }) }); }; - const chartMsgClass = classNames({ [prefixCls]: !isTable }); + const chartMsgClass = classNames({ + [prefixCls]: ![MsgContentTypeEnum.TABLE, MsgContentTypeEnum.MARKDOWN].includes( + getMsgContentType() as MsgContentTypeEnum + ), + }); const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined; const entityName = elementMatches?.find((item: any) => item.element?.type === 'ID')?.element ?.name; const isEntityMode = - (queryMode === 'TAG_LIST_FILTER' || queryMode === 'METRIC_ID') && + (queryMode === 'TAG_LIST_FILTER' || queryMode === 'METRIC_TAG') && typeof entityId === 'string' && entityName !== undefined; - const existDrillDownDimension = queryMode.includes('METRIC') && !isText && !isEntityMode; + const existDrillDownDimension = + queryMode.includes('METRIC') && + getMsgContentType() !== MsgContentTypeEnum.TEXT && + !isEntityMode; const recommendMetrics = chatContext?.metrics?.filter(metric => queryColumns.every(queryColumn => queryColumn.nameEn !== metric.bizName) @@ -258,7 +316,9 @@ const ChatMsg: React.FC = ({ queryId, data, chartIndex, triggerResize }) {(isMultipleMetric || existDrillDownDimension) && (
{isMultipleMetric && (