[feature](webapp) add copilot and modify domain to model

This commit is contained in:
williamhliu
2023-08-15 20:04:04 +08:00
parent 2732d8fee1
commit 86b93876c7
43 changed files with 738 additions and 431 deletions

View File

@@ -10,6 +10,7 @@ type Props = {
parseInfoOptions: ChatContextType[];
parseTip: string;
currentParseInfo?: ChatContextType;
optionMode?: boolean;
onSelectParseInfo: (parseInfo: ChatContextType) => void;
};
@@ -20,6 +21,7 @@ const ParseTip: React.FC<Props> = ({
parseInfoOptions,
parseTip,
currentParseInfo,
optionMode,
onSelectParseInfo,
}) => {
const prefixCls = `${PREFIX_CLS}-item`;
@@ -38,7 +40,7 @@ const ParseTip: React.FC<Props> = ({
const getTipNode = (parseInfo: ChatContextType, isOptions?: boolean, index?: number) => {
const {
domainName,
modelName,
dateInfo,
dimensionFilters,
dimensions,
@@ -70,6 +72,7 @@ const ParseTip: React.FC<Props> = ({
[`${prefixCls}-tip-item-option`]: isOptions,
});
const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined;
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
const entityName = elementMatches?.find(item => item.element?.type === 'ID')?.element.name;
@@ -106,7 +109,10 @@ const ParseTip: React.FC<Props> = ({
</div>
) : (
<>
{queryMode === 'METRIC_ENTITY' || queryMode === 'ENTITY_DETAIL' ? (
{queryMode.includes('ENTITY') &&
typeof entityId === 'string' &&
!!entityAlias &&
!!entityName ? (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}</div>
<div className={itemValueClass}>{entityName}</div>
@@ -114,7 +120,7 @@ const ParseTip: React.FC<Props> = ({
) : (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}></div>
<div className={itemValueClass}>{domainName}</div>
<div className={itemValueClass}>{modelName}</div>
</div>
)}
{modeName === '算指标' && metric && (
@@ -180,10 +186,12 @@ const ParseTip: React.FC<Props> = ({
let tipNode: ReactNode;
if (parseInfoOptions.length > 1) {
if (parseInfoOptions.length > 1 || optionMode) {
tipNode = (
<div className={`${prefixCls}-multi-options`}>
<div></div>
<div>
<strong></strong>
</div>
<div className={`${prefixCls}-options`}>
{parseInfoOptions.map((item, index) => getTipNode(item, true, index))}
</div>

View File

@@ -9,12 +9,13 @@ import ExecuteItem from './ExecuteItem';
type Props = {
msg: string;
conversationId?: number;
domainId?: number;
modelId?: number;
filter?: any[];
isLastMessage?: boolean;
msgData?: MsgDataType;
isMobileMode?: boolean;
triggerResize?: boolean;
parseOptions?: ChatContextType[];
onMsgDataLoaded?: (data: MsgDataType, valid: boolean) => void;
onUpdateMessageScroll?: () => void;
};
@@ -22,19 +23,20 @@ type Props = {
const ChatItem: React.FC<Props> = ({
msg,
conversationId,
domainId,
modelId,
filter,
isLastMessage,
isMobileMode,
triggerResize,
msgData,
parseOptions,
onMsgDataLoaded,
onUpdateMessageScroll,
}) => {
const [data, setData] = useState<MsgDataType>();
const [parseLoading, setParseLoading] = useState(false);
const [parseInfo, setParseInfo] = useState<ChatContextType>();
const [parseInfoOptions, setParseInfoOptions] = useState<ChatContextType[]>([]);
const [parseInfoOptions, setParseInfoOptions] = useState<ChatContextType[]>(parseOptions || []);
const [parseTip, setParseTip] = useState('');
const [executeLoading, setExecuteLoading] = useState(false);
const [executeTip, setExecuteTip] = useState('');
@@ -68,20 +70,43 @@ const ChatItem: React.FC<Props> = ({
return true;
};
const onExecute = async (parseInfoValue: ChatContextType, isSwitch?: boolean) => {
const onExecute = async (
parseInfoValue: ChatContextType,
parseInfoOptions?: ChatContextType[]
) => {
setExecuteMode(true);
setExecuteLoading(true);
const { data } = await chatExecute(msg, conversationId!, parseInfoValue);
setExecuteLoading(false);
const valid = updateData(data);
if (onMsgDataLoaded && !isSwitch) {
onMsgDataLoaded({ ...data.data, chatContext: parseInfoValue }, valid);
if (onMsgDataLoaded) {
let parseOptions: ChatContextType[] = parseInfoOptions || [];
if (
parseInfoOptions &&
parseInfoOptions.length > 1 &&
(parseInfoOptions[0].queryMode.includes('METRIC') ||
parseInfoOptions[0].queryMode.includes('ENTITY'))
) {
parseOptions = parseInfoOptions.filter(
(item, index) =>
index === 0 ||
(!item.queryMode.includes('METRIC') && !item.queryMode.includes('ENTITY'))
);
}
onMsgDataLoaded(
{
...data.data,
chatContext: parseInfoValue,
parseOptions: parseOptions.length > 1 ? parseOptions.slice(1) : undefined,
},
valid
);
}
};
const onSendMsg = async () => {
setParseLoading(true);
const { data: parseData } = await chatParse(msg, conversationId, domainId, filter);
const { data: parseData } = await chatParse(msg, conversationId, modelId, filter);
setParseLoading(false);
const { code, data } = parseData || {};
const { state, selectedParses } = data || {};
@@ -91,7 +116,7 @@ const ChatItem: React.FC<Props> = ({
selectedParses == null ||
selectedParses.length === 0 ||
(selectedParses.length === 1 &&
!selectedParses[0]?.domainName &&
!selectedParses[0]?.modelName &&
!selectedParses[0]?.properties?.CONTEXT?.plugin?.name &&
selectedParses[0]?.queryMode !== 'WEB_PAGE')
) {
@@ -102,15 +127,13 @@ const ChatItem: React.FC<Props> = ({
onUpdateMessageScroll();
}
setParseInfoOptions(selectedParses || []);
if (selectedParses.length === 1) {
const parseInfoValue = selectedParses[0];
setParseInfo(parseInfoValue);
onExecute(parseInfoValue);
}
const parseInfoValue = selectedParses[0];
setParseInfo(parseInfoValue);
onExecute(parseInfoValue, selectedParses);
};
useEffect(() => {
if (data !== undefined) {
if (data !== undefined || parseOptions !== undefined || executeTip !== '') {
return;
}
if (msgData) {
@@ -124,7 +147,7 @@ const ChatItem: React.FC<Props> = ({
const onSwitchEntity = async (entityId: string) => {
setEntitySwitching(true);
const res = await switchEntity(entityId, data?.chatContext?.domainId, conversationId || 0);
const res = await switchEntity(entityId, data?.chatContext?.modelId, conversationId || 0);
setEntitySwitching(false);
setData(res.data.data);
};
@@ -135,7 +158,7 @@ const ChatItem: React.FC<Props> = ({
const onSelectParseInfo = async (parseInfoValue: ChatContextType) => {
setParseInfo(parseInfoValue);
onExecute(parseInfoValue, parseInfo !== undefined);
onExecute(parseInfoValue);
if (onUpdateMessageScroll) {
onUpdateMessageScroll();
}
@@ -148,9 +171,10 @@ const ChatItem: React.FC<Props> = ({
<div className={`${prefixCls}-content`}>
<ParseTip
parseLoading={parseLoading}
parseInfoOptions={parseInfoOptions}
parseInfoOptions={parseOptions || parseInfoOptions.slice(0, 1)}
parseTip={parseTip}
currentParseInfo={parseInfo}
optionMode={parseOptions !== undefined}
onSelectParseInfo={onSelectParseInfo}
/>
</div>

View File

@@ -1,11 +1,11 @@
import { PREFIX_CLS } from '../../../common/constants';
type Props = {
domain: string;
onApplyAuth?: (domain: string) => void;
model: string;
onApplyAuth?: (model: string) => void;
};
const ApplyAuth: React.FC<Props> = ({ domain, onApplyAuth }) => {
const ApplyAuth: React.FC<Props> = ({ model, onApplyAuth }) => {
const prefixCls = `${PREFIX_CLS}-apply-auth`;
return (
@@ -15,7 +15,7 @@ const ApplyAuth: React.FC<Props> = ({ domain, onApplyAuth }) => {
<span
className={`${prefixCls}-apply`}
onClick={() => {
onApplyAuth(domain);
onApplyAuth(model);
}}
>

View File

@@ -15,7 +15,7 @@ type Props = {
drillDownDimension?: DrillDownDimensionType;
loading: boolean;
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
onApplyAuth?: (domain: string) => void;
onApplyAuth?: (model: string) => void;
};
const BarChart: React.FC<Props> = ({
@@ -152,7 +152,7 @@ const BarChart: React.FC<Props> = ({
if (metricColumn && !metricColumn?.authorized) {
return (
<NoPermissionChart
domain={entityInfo?.domainInfo.name || ''}
model={entityInfo?.modelInfo.name || ''}
chartType="barChart"
onApplyAuth={onApplyAuth}
/>
@@ -193,11 +193,9 @@ const BarChart: React.FC<Props> = ({
<Spin spinning={loading}>
<div className={`${prefixCls}-chart`} ref={chartRef} />
</Spin>
{(queryMode === 'METRIC_DOMAIN' ||
queryMode === 'METRIC_FILTER' ||
queryMode === 'METRIC_GROUPBY') && (
{queryMode.includes('METRIC') && (
<DrillDownDimensions
domainId={chatContext.domainId}
modelId={chatContext.modelId}
drillDownDimension={drillDownDimension}
dimensionFilters={chatContext.dimensionFilters}
onSelectDimension={onSelectDimension}

View File

@@ -26,7 +26,7 @@ const Message: React.FC<Props> = ({
}) => {
const prefixCls = `${PREFIX_CLS}-message`;
const { domainName, dateInfo, dimensionFilters } = chatContext || {};
const { modelName, dateInfo, dimensionFilters } = chatContext || {};
const { startDate, endDate } = dateInfo || {};
const entityInfoList =
@@ -67,7 +67,7 @@ const Message: React.FC<Props> = ({
<div className={`${prefixCls}-main-entity-info`}>
<div className={`${prefixCls}-info-item`}>
<div className={`${prefixCls}-info-name`}></div>
<div className={`${prefixCls}-info-value`}>{domainName}</div>
<div className={`${prefixCls}-info-value`}>{modelName}</div>
</div>
<div className={`${prefixCls}-info-item`}>
<div className={`${prefixCls}-info-name`}></div>

View File

@@ -10,7 +10,7 @@
margin-bottom: 6px;
}
&-domain-name {
&-model-name {
color: var(--text-color);
margin-left: 4px;
font-weight: 500;

View File

@@ -13,7 +13,7 @@ type Props = {
drillDownDimension?: DrillDownDimensionType;
loading: boolean;
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
onApplyAuth?: (domain: string) => void;
onApplyAuth?: (model: string) => void;
};
const MetricCard: React.FC<Props> = ({
@@ -64,7 +64,7 @@ const MetricCard: React.FC<Props> = ({
<div className={indicatorClass}>
<div className={`${prefixCls}-date-range`}>{startDate}</div>
{indicatorColumn && !indicatorColumn?.authorized ? (
<ApplyAuth domain={entityInfo?.domainInfo.name || ''} onApplyAuth={onApplyAuth} />
<ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />
) : (
<div className={`${prefixCls}-indicator-value`}>
{formatMetric(queryResults?.[0]?.[indicatorColumnName]) || '-'}
@@ -79,10 +79,10 @@ const MetricCard: React.FC<Props> = ({
)}
</div>
</Spin>
{(queryMode === 'METRIC_DOMAIN' || queryMode === 'METRIC_FILTER') && (
{queryMode.includes('METRIC') && (
<div className={`${prefixCls}-drill-down-dimensions`}>
<DrillDownDimensions
domainId={chatContext.domainId}
modelId={chatContext.modelId}
dimensionFilters={chatContext.dimensionFilters}
drillDownDimension={drillDownDimension}
onSelectDimension={onSelectDimension}

View File

@@ -109,7 +109,7 @@
&-drill-down-dimensions {
position: absolute;
bottom: -44px;
left: -16;
bottom: -38px;
left: 0;
}
}

View File

@@ -14,17 +14,17 @@ import { ColumnType } from '../../../common/type';
import NoPermissionChart from '../NoPermissionChart';
type Props = {
domain?: string;
model?: string;
dateColumnName: string;
categoryColumnName: string;
metricField: ColumnType;
resultList: any[];
triggerResize?: boolean;
onApplyAuth?: (domain: string) => void;
onApplyAuth?: (model: string) => void;
};
const MetricTrendChart: React.FC<Props> = ({
domain,
model,
dateColumnName,
categoryColumnName,
metricField,
@@ -204,7 +204,7 @@ const MetricTrendChart: React.FC<Props> = ({
return (
<div>
{!metricField.authorized ? (
<NoPermissionChart domain={domain || ''} onApplyAuth={onApplyAuth} />
<NoPermissionChart model={model || ''} onApplyAuth={onApplyAuth} />
) : (
<div className={`${prefixCls}-flow-trend-chart`} ref={chartRef} />
)}

View File

@@ -15,7 +15,7 @@ type Props = {
data: MsgDataType;
chartIndex: number;
triggerResize?: boolean;
onApplyAuth?: (domain: string) => void;
onApplyAuth?: (model: string) => void;
};
const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApplyAuth }) => {
@@ -36,6 +36,7 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
const [currentDateOption, setCurrentDateOption] = useState<number>(initialDateOption);
const [dimensions, setDimensions] = useState<FieldType[]>(chatContext?.dimensions);
const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
const [aggregateInfoValue, setAggregateInfoValue] = useState<any>(aggregateInfo);
const [dateModeValue, setDateModeValue] = useState(dateMode);
const [loading, setLoading] = useState(false);
@@ -72,6 +73,7 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
if (data.code === 200) {
setColumns(data.data?.queryColumns || []);
setDataSource(data.data?.queryResults || []);
setAggregateInfoValue(data.data?.aggregateInfo);
}
};
@@ -172,7 +174,9 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
</div>
)}
</div>
{aggregateInfo?.metricInfos?.length > 0 && <MetricInfo aggregateInfo={aggregateInfo} />}
{aggregateInfoValue?.metricInfos?.length > 0 && (
<MetricInfo aggregateInfo={aggregateInfoValue} />
)}
<div className={`${prefixCls}-date-options`}>
{dateOptions.map((dateOption: { label: string; value: number }, index: number) => {
const dateOptionClass = classNames(`${prefixCls}-date-option`, {
@@ -205,7 +209,7 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
<Table data={{ ...data, queryResults: dataSource }} onApplyAuth={onApplyAuth} />
) : (
<MetricTrendChart
domain={entityInfo?.domainInfo.name}
model={entityInfo?.modelInfo.name}
dateColumnName={dateColumnName}
categoryColumnName={categoryColumnName}
metricField={currentMetricField}
@@ -215,11 +219,9 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
/>
)}
</Spin>
{(queryMode === 'METRIC_DOMAIN' ||
queryMode === 'METRIC_FILTER' ||
queryMode === 'METRIC_GROUPBY') && (
{queryMode.includes('METRIC') && (
<DrillDownDimensions
domainId={chatContext.domainId}
modelId={chatContext.modelId}
drillDownDimension={drillDownDimension}
dimensionFilters={chatContext.dimensionFilters}
onSelectDimension={onSelectDimension}

View File

@@ -3,12 +3,12 @@ import { CLS_PREFIX } from '../../../common/constants';
import ApplyAuth from '../ApplyAuth';
type Props = {
domain: string;
model: string;
chartType?: string;
onApplyAuth?: (domain: string) => void;
onApplyAuth?: (model: string) => void;
};
const NoPermissionChart: React.FC<Props> = ({ domain, chartType, onApplyAuth }) => {
const NoPermissionChart: React.FC<Props> = ({ model, chartType, onApplyAuth }) => {
const prefixCls = `${CLS_PREFIX}-no-permission-chart`;
const chartHolderClass = classNames(`${prefixCls}-holder`, {
@@ -19,7 +19,7 @@ const NoPermissionChart: React.FC<Props> = ({ domain, chartType, onApplyAuth })
<div className={prefixCls}>
<div className={chartHolderClass} />
<div className={`${prefixCls}-no-permission`}>
<ApplyAuth domain={domain} onApplyAuth={onApplyAuth} />
<ApplyAuth model={model} onApplyAuth={onApplyAuth} />
</div>
</div>
);

View File

@@ -8,7 +8,7 @@ import { SizeType } from 'antd/es/config-provider/SizeContext';
type Props = {
data: MsgDataType;
size?: SizeType;
onApplyAuth?: (domain: string) => void;
onApplyAuth?: (model: string) => void;
};
const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
@@ -24,9 +24,7 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
title: name || nameEn,
render: (value: string | number) => {
if (!authorized) {
return (
<ApplyAuth domain={entityInfo?.domainInfo.name || ''} onApplyAuth={onApplyAuth} />
);
return <ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />;
}
if (dataFormatType === 'percent') {
return (
@@ -71,7 +69,7 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
columns={tableColumns}
dataSource={queryResults}
style={{ width: '100%' }}
scroll={{ x: 'max-content' }}
// scroll={{ x: 'max-content' }}
rowClassName={getRowClassName}
size={size}
/>

View File

@@ -3,7 +3,7 @@
@table-prefix-cls: ~'@{supersonic-chat-prefix}-table';
.@{table-prefix-cls} {
margin-top: 20px;
margin-top: 16px;
margin-bottom: 20px;
&-photo {

View File

@@ -35,10 +35,15 @@ const ChatMsg: React.FC<Props> = ({ question, data, chartIndex, isMobileMode, tr
const metricFields = columns.filter(item => item.showType === 'NUMBER');
const isMetricCard =
(queryMode === 'METRIC_DOMAIN' || queryMode === 'METRIC_FILTER') &&
queryMode.includes('METRIC') &&
(singleData || chatContext?.dateInfo?.startDate === chatContext?.dateInfo?.endDate);
const isText = columns.length === 1 && columns[0].showType === 'CATEGORY' && singleData;
const isText =
columns.length === 1 &&
columns[0].showType === 'CATEGORY' &&
!queryMode.includes('METRIC') &&
!queryMode.includes('ENTITY') &&
singleData;
const onLoadData = async (value: any) => {
setLoading(true);

View File

@@ -7,7 +7,7 @@ import { DownOutlined } from '@ant-design/icons';
import classNames from 'classnames';
type Props = {
domainId: number;
modelId: number;
drillDownDimension?: DrillDownDimensionType;
isMetricCard?: boolean;
dimensionFilters?: FilterItemType[];
@@ -17,7 +17,7 @@ type Props = {
const MAX_DIMENSION_COUNT = 20;
const DrillDownDimensions: React.FC<Props> = ({
domainId,
modelId,
drillDownDimension,
isMetricCard,
dimensionFilters,
@@ -30,7 +30,7 @@ const DrillDownDimensions: React.FC<Props> = ({
const prefixCls = `${CLS_PREFIX}-drill-down-dimensions`;
const initData = async () => {
const res = await queryDrillDownDimensions(domainId);
const res = await queryDrillDownDimensions(modelId);
setDimensions(
res.data.data.dimensions
.filter(dimension => !dimensionFilters?.some(filter => filter.name === dimension.name))

View File

@@ -10,16 +10,16 @@ import classNames from 'classnames';
type Props = {
entityId: string | number;
domainId: number;
domainName: string;
modelId: number;
modelName: string;
isMobileMode?: boolean;
onSelect: (option: string) => void;
};
const RecommendOptions: React.FC<Props> = ({
entityId,
domainId,
domainName,
modelId,
modelName,
isMobileMode,
onSelect,
}) => {
@@ -30,7 +30,7 @@ const RecommendOptions: React.FC<Props> = ({
const initData = async () => {
setLoading(true);
const res = await queryEntities(entityId, domainId);
const res = await queryEntities(entityId, modelId);
setLoading(false);
setData(res.data.data);
};
@@ -51,7 +51,7 @@ const RecommendOptions: React.FC<Props> = ({
<div className={`${prefixCls}-item-name-column`}>
<Avatar
shape="square"
icon={<IconFont type={domainName === '艺人库' ? 'icon-geshou' : 'icon-zhuanji'} />}
icon={<IconFont type={modelName === '艺人库' ? 'icon-geshou' : 'icon-zhuanji'} />}
src={record.url}
/>
<div className={`${prefixCls}-entity-name`}>
@@ -64,7 +64,7 @@ const RecommendOptions: React.FC<Props> = ({
},
};
const playCntColumnIdex = domainName.includes('歌曲')
const playCntColumnIdex = modelName.includes('歌曲')
? 'tme3platAvgLogYyPlayCnt'
: 'tme3platJsPlayCnt';
@@ -72,7 +72,7 @@ const RecommendOptions: React.FC<Props> = ({
? [basicColumn]
: [
basicColumn,
domainName.includes('艺人')
modelName.includes('艺人')
? {
dataIndex: 'onlineSongCnt',
key: 'onlineSongCnt',
@@ -95,7 +95,7 @@ const RecommendOptions: React.FC<Props> = ({
dataIndex: playCntColumnIdex,
key: playCntColumnIdex,
align: 'center',
title: domainName.includes('歌曲') ? '近7天日均运营播放量' : '昨日结算播放量',
title: modelName.includes('歌曲') ? '近7天日均运营播放量' : '昨日结算播放量',
render: (value: string) => {
return value ? getFormattedValue(+value) : '-';
},

View File

@@ -26,21 +26,22 @@ const Tools: React.FC<Props> = ({
onChangeChart,
}) => {
const [recommendOptionsOpen, setRecommendOptionsOpen] = useState(false);
const { queryColumns, queryResults, queryId, chatContext, queryMode } = data || {};
const { queryColumns, queryResults, queryId, chatContext, queryMode, entityInfo } = data || {};
const [score, setScore] = useState(scoreValue || 0);
const prefixCls = `${CLS_PREFIX}-tools`;
const singleData = queryResults.length === 1;
const isMetricCard =
queryMode.includes('METRIC') &&
(singleData || chatContext?.dateInfo?.startDate === chatContext?.dateInfo?.endDate);
const noDashboard =
(queryColumns?.length === 1 &&
queryColumns[0].showType === 'CATEGORY' &&
queryResults?.length === 1) ||
(!queryMode.includes('METRIC') && !queryMode.includes('ENTITY'));
console.log(
'chatContext?.properties?.CONTEXT?.plugin?.name',
chatContext?.properties?.CONTEXT?.plugin?.name
);
(!queryMode.includes('METRIC') && !queryMode.includes('ENTITY')) ||
isMetricCard;
const changeChart = () => {
onChangeChart();
@@ -74,13 +75,13 @@ const Tools: React.FC<Props> = ({
return (
<div className={prefixCls}>
{/* {isLastMessage && chatContext?.domainId && entityInfo?.entityId && (
{/* {isLastMessage && chatContext?.modelId && entityInfo?.entityId && (
<Popover
content={
<RecommendOptions
entityId={entityInfo.entityId}
domainId={chatContext.domainId}
domainName={chatContext.domainName}
modelId={chatContext.modelId}
modelName={chatContext.modelName}
isMobileMode={isMobileMode}
onSelect={switchEntity}
/>
@@ -105,7 +106,7 @@ const Tools: React.FC<Props> = ({
</Button>
)}
{isLastMessage && (
{isLastMessage && !isMetricCard && (
<div className={`${prefixCls}-feedback`}>
<div></div>
<LikeOutlined className={likeClass} onClick={like} />