mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 11:07:06 +00:00
(improvement)(chat-sdk) add parse error detail (#1476)
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { Dayjs } from 'dayjs';
|
||||||
|
|
||||||
export type SearchRecommendItem = {
|
export type SearchRecommendItem = {
|
||||||
complete: boolean;
|
complete: boolean;
|
||||||
modelId: number;
|
modelId: number;
|
||||||
@@ -257,3 +259,5 @@ export type ParseTimeCostType = {
|
|||||||
parseTime: number;
|
parseTime: number;
|
||||||
sqlTime: number;
|
sqlTime: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RangeValue = [Dayjs, Dayjs];
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ 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 { Button, DatePicker, Row, Col } from 'antd';
|
import { Button, DatePicker, Row, Col } from 'antd';
|
||||||
import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
import { CheckCircleFilled, CloseCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
||||||
import Loading from './Loading';
|
import Loading from './Loading';
|
||||||
import FilterItem from './FilterItem';
|
import FilterItem from './FilterItem';
|
||||||
import MarkDown from '../ChatMsg/MarkDown';
|
import MarkDown from '../ChatMsg/MarkDown';
|
||||||
@@ -37,11 +37,9 @@ type Props = {
|
|||||||
|
|
||||||
const MAX_OPTION_VALUES_COUNT = 2;
|
const MAX_OPTION_VALUES_COUNT = 2;
|
||||||
|
|
||||||
|
|
||||||
type RangeValue = [Dayjs, Dayjs];
|
type RangeValue = [Dayjs, Dayjs];
|
||||||
type RangeKeys = '近7日' | '近14日' | '近30日' | '本周' | '本月' | '上月' | '本季度' | '本年';
|
type RangeKeys = '近7日' | '近14日' | '近30日' | '本周' | '本月' | '上月' | '本季度' | '本年';
|
||||||
|
|
||||||
|
|
||||||
const ParseTip: React.FC<Props> = ({
|
const ParseTip: React.FC<Props> = ({
|
||||||
parseLoading,
|
parseLoading,
|
||||||
parseInfoOptions,
|
parseInfoOptions,
|
||||||
@@ -60,24 +58,33 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
onFiltersChange,
|
onFiltersChange,
|
||||||
onDateInfoChange,
|
onDateInfoChange,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
handlePresetClick
|
handlePresetClick,
|
||||||
}) => {
|
}) => {
|
||||||
const ranges: Record<RangeKeys, RangeValue> = {
|
const ranges: Record<RangeKeys, RangeValue> = {
|
||||||
'近7日': [dayjs().subtract(7, 'day'), dayjs()],
|
近7日: [dayjs().subtract(7, 'day'), dayjs()],
|
||||||
'近14日': [dayjs().subtract(14, 'day'), dayjs()],
|
近14日: [dayjs().subtract(14, 'day'), dayjs()],
|
||||||
'近30日': [dayjs().subtract(30, 'day'), dayjs()],
|
近30日: [dayjs().subtract(30, 'day'), dayjs()],
|
||||||
'本周': [dayjs().startOf('week'), dayjs().endOf('week')],
|
本周: [dayjs().startOf('week'), dayjs().endOf('week')],
|
||||||
'本月': [dayjs().startOf('month'), dayjs().endOf('month')],
|
本月: [dayjs().startOf('month'), dayjs().endOf('month')],
|
||||||
'上月': [dayjs().subtract(1, 'month').startOf('month'), dayjs().subtract(1, 'month').endOf('month')],
|
上月: [
|
||||||
'本季度': [dayjs().startOf('quarter'), dayjs().endOf('quarter')], // 使用 quarterOfYear 插件
|
dayjs().subtract(1, 'month').startOf('month'),
|
||||||
'本年': [dayjs().startOf('year'), dayjs().endOf('year')],
|
dayjs().subtract(1, 'month').endOf('month'),
|
||||||
|
],
|
||||||
|
本季度: [dayjs().startOf('quarter'), dayjs().endOf('quarter')], // 使用 quarterOfYear 插件
|
||||||
|
本年: [dayjs().startOf('year'), dayjs().endOf('year')],
|
||||||
};
|
};
|
||||||
|
|
||||||
const prefixCls = `${PREFIX_CLS}-item`;
|
const prefixCls = `${PREFIX_CLS}-item`;
|
||||||
const getNode = (tipTitle: ReactNode, tipNode?: ReactNode) => {
|
|
||||||
|
const getNode = (tipTitle: ReactNode, tipNode?: ReactNode, failed?: boolean) => {
|
||||||
return (
|
return (
|
||||||
<div className={`${prefixCls}-parse-tip`}>
|
<div className={`${prefixCls}-parse-tip`}>
|
||||||
<div className={`${prefixCls}-title-bar`}>
|
<div className={`${prefixCls}-title-bar`}>
|
||||||
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
{!failed ? (
|
||||||
|
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
||||||
|
) : (
|
||||||
|
<CloseCircleFilled className={`${prefixCls}-step-error-icon`} />
|
||||||
|
)}
|
||||||
<div className={`${prefixCls}-step-title`}>
|
<div className={`${prefixCls}-step-title`}>
|
||||||
{tipTitle}
|
{tipTitle}
|
||||||
{tipNode === undefined && <Loading />}
|
{tipNode === undefined && <Loading />}
|
||||||
@@ -85,8 +92,11 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
{(tipNode || tipNode === null) && (
|
{(tipNode || tipNode === null) && (
|
||||||
<div
|
<div
|
||||||
className={`${prefixCls}-content-container ${tipNode === null ? `${prefixCls}-empty-content-container` : ''
|
className={classNames(
|
||||||
}`}
|
`${prefixCls}-content-container`,
|
||||||
|
tipNode === null && `${prefixCls}-empty-content-container`,
|
||||||
|
failed && `${prefixCls}-content-container-failed`
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{tipNode}
|
{tipNode}
|
||||||
</div>
|
</div>
|
||||||
@@ -107,7 +117,8 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
<span className={`${prefixCls}-title-tip`}>(耗时: {parseTimeCost}ms)</span>
|
<span className={`${prefixCls}-title-tip`}>(耗时: {parseTimeCost}ms)</span>
|
||||||
)}
|
)}
|
||||||
</>,
|
</>,
|
||||||
parseTip
|
parseTip,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,9 +178,9 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{(queryMode?.includes('ENTITY') || queryMode === 'LLM_S2SQL') &&
|
{(queryMode?.includes('ENTITY') || queryMode === 'LLM_S2SQL') &&
|
||||||
typeof entityId === 'string' &&
|
typeof entityId === 'string' &&
|
||||||
!!entityAlias &&
|
!!entityAlias &&
|
||||||
!!entityName ? (
|
!!entityName ? (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}:</div>
|
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}:</div>
|
||||||
<div className={itemValueClass}>{entityName}</div>
|
<div className={itemValueClass}>{entityName}</div>
|
||||||
@@ -262,7 +273,7 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
format="YYYY/MM/DD"
|
format="YYYY/MM/DD"
|
||||||
renderExtraFooter={() => (
|
renderExtraFooter={() => (
|
||||||
<Row gutter={[28, 28]}>
|
<Row gutter={[28, 28]}>
|
||||||
{Object.keys(ranges).map((key) => (
|
{Object.keys(ranges).map(key => (
|
||||||
<Col key={key}>
|
<Col key={key}>
|
||||||
<label
|
<label
|
||||||
style={{
|
style={{
|
||||||
@@ -271,9 +282,10 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
color: '#33BDFC',
|
color: '#33BDFC',
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderStyle: 'solid',
|
borderStyle: 'solid',
|
||||||
cursor: 'pointer'
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
onClick={() => handlePresetClick(ranges[key as RangeKeys])}>
|
onClick={() => handlePresetClick(ranges[key as RangeKeys])}
|
||||||
|
>
|
||||||
{key}
|
{key}
|
||||||
</label>
|
</label>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -281,8 +293,6 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{filters?.map((filter: any, index: number) => (
|
{filters?.map((filter: any, index: number) => (
|
||||||
@@ -343,8 +353,9 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
<div className={`${prefixCls}-content-options`}>
|
<div className={`${prefixCls}-content-options`}>
|
||||||
{parseInfoOptions.map((parseInfo, index) => (
|
{parseInfoOptions.map((parseInfo, index) => (
|
||||||
<div
|
<div
|
||||||
className={`${prefixCls}-content-option ${parseInfo.id === currentParseInfo?.id ? `${prefixCls}-content-option-active` : ''
|
className={`${prefixCls}-content-option ${
|
||||||
}`}
|
parseInfo.id === currentParseInfo?.id ? `${prefixCls}-content-option-active` : ''
|
||||||
|
}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onSelectParseInfo(parseInfo);
|
onSelectParseInfo(parseInfo);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
MsgDataType,
|
MsgDataType,
|
||||||
ParseStateEnum,
|
ParseStateEnum,
|
||||||
ParseTimeCostType,
|
ParseTimeCostType,
|
||||||
|
RangeValue,
|
||||||
SimilarQuestionType,
|
SimilarQuestionType,
|
||||||
} from '../../common/type';
|
} from '../../common/type';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -79,6 +80,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
const [dataCache, setDataCache] = useState<Record<number, { tip: string; data?: MsgDataType }>>(
|
const [dataCache, setDataCache] = useState<Record<number, { tip: string; data?: MsgDataType }>>(
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
const [selectedRange, setSelectedRange] = useState<RangeValue | null>(null);
|
||||||
|
|
||||||
const prefixCls = `${PREFIX_CLS}-item`;
|
const prefixCls = `${PREFIX_CLS}-item`;
|
||||||
|
|
||||||
@@ -167,7 +169,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, parseTimeCost } = data || {};
|
const { state, selectedParses, candidateParses, queryId, parseTimeCost, errorMsg } = data || {};
|
||||||
const parses = selectedParses?.concat(candidateParses || []) || [];
|
const parses = selectedParses?.concat(candidateParses || []) || [];
|
||||||
if (
|
if (
|
||||||
code !== 200 ||
|
code !== 200 ||
|
||||||
@@ -175,7 +177,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
!parses.length ||
|
!parses.length ||
|
||||||
(!parses[0]?.properties?.type && !parses[0]?.queryMode)
|
(!parses[0]?.properties?.type && !parses[0]?.queryMode)
|
||||||
) {
|
) {
|
||||||
setParseTip(PARSE_ERROR_TIP);
|
setParseTip(state === ParseStateEnum.FAILED && errorMsg ? errorMsg : PARSE_ERROR_TIP);
|
||||||
setParseInfo({ queryId } as any);
|
setParseInfo({ queryId } as any);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -234,9 +236,6 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
setDimensionFilters(dimensionFilters);
|
setDimensionFilters(dimensionFilters);
|
||||||
};
|
};
|
||||||
|
|
||||||
type RangeValue = [Dayjs, Dayjs];
|
|
||||||
const [selectedRange, setSelectedRange] = useState<RangeValue | null>(null);
|
|
||||||
|
|
||||||
const onDateInfoChange = (dates: [Dayjs | null, Dayjs | null] | null) => {
|
const onDateInfoChange = (dates: [Dayjs | null, Dayjs | null] | null) => {
|
||||||
if (dates && dates[0] && dates[1]) {
|
if (dates && dates[0] && dates[1]) {
|
||||||
const [start, end] = dates;
|
const [start, end] = dates;
|
||||||
@@ -264,7 +263,6 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const onRefresh = async () => {
|
const onRefresh = async () => {
|
||||||
setEntitySwitchLoading(true);
|
setEntitySwitchLoading(true);
|
||||||
const { dimensions, metrics, id, queryId } = parseInfo || {};
|
const { dimensions, metrics, id, queryId } = parseInfo || {};
|
||||||
@@ -391,7 +389,8 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{(parseTip !== '' || (executeMode && !executeLoading)) &&
|
{executeMode &&
|
||||||
|
!executeLoading &&
|
||||||
!isSimpleMode &&
|
!isSimpleMode &&
|
||||||
parseInfo?.queryMode !== 'PLAIN_TEXT' && (
|
parseInfo?.queryMode !== 'PLAIN_TEXT' && (
|
||||||
<SimilarQuestionItem
|
<SimilarQuestionItem
|
||||||
|
|||||||
@@ -162,6 +162,11 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-step-error-icon {
|
||||||
|
color: var(--error-color);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
&-content-container {
|
&-content-container {
|
||||||
margin: 2px 0 2px 7px;
|
margin: 2px 0 2px 7px;
|
||||||
padding: 10px 0 4px 18px;
|
padding: 10px 0 4px 18px;
|
||||||
@@ -173,6 +178,10 @@
|
|||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-content-container-failed {
|
||||||
|
border-left: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
&-auth-tip {
|
&-auth-tip {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--text-color-secondary);
|
color: var(--text-color-secondary);
|
||||||
|
|||||||
Reference in New Issue
Block a user