(improvement)(chat-sdk) add parse error detail (#1476)

This commit is contained in:
williamhliu
2024-07-29 19:22:24 +08:00
committed by GitHub
parent 9a14728152
commit 9e4513f7ca
4 changed files with 57 additions and 34 deletions

View File

@@ -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];

View File

@@ -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);
}} }}

View File

@@ -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

View File

@@ -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);