diff --git a/webapp/packages/chat-sdk/src/Chat/ChatFooter/index.tsx b/webapp/packages/chat-sdk/src/Chat/ChatFooter/index.tsx index 51aa35f65..39e5f9f42 100644 --- a/webapp/packages/chat-sdk/src/Chat/ChatFooter/index.tsx +++ b/webapp/packages/chat-sdk/src/Chat/ChatFooter/index.tsx @@ -21,6 +21,7 @@ type Props = { onSendMsg: (msg: string, modelId?: number) => void; onAddConversation: (agent?: AgentType) => void; onSelectAgent: (agent: AgentType) => void; + onOpenShowcase: () => void; }; const { OptGroup, Option } = Select; @@ -47,6 +48,7 @@ const ChatFooter: ForwardRefRenderFunction = ( onSendMsg, onAddConversation, onSelectAgent, + onOpenShowcase, }, ref ) => { @@ -313,14 +315,24 @@ const ChatFooter: ForwardRefRenderFunction = (
智能助理
+ {!isMobile && ( +
+ +
showcase
+
+ )}
{ onInputMsgChange(value); diff --git a/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx b/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx index f0441a328..530cae0cd 100644 --- a/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx +++ b/webapp/packages/chat-sdk/src/Chat/MessageContainer/index.tsx @@ -22,7 +22,8 @@ type Props = { data: MsgDataType, questionId: string | number, question: string, - valid: boolean + valid: boolean, + isRefresh?: boolean ) => void; onSendMsg: (value: string) => void; }; @@ -72,6 +73,7 @@ const MessageContainer: React.FC = ({ type, msg, msgValue, + score, identityMsg, msgData, filters, @@ -93,13 +95,14 @@ const MessageContainer: React.FC = ({ conversationId={chatId} modelId={modelId} agentId={agentId} + score={score} filter={filters} isLastMessage={index === messageList.length - 1} triggerResize={triggerResize} isDeveloper={isDeveloper} integrateSystem={integrateSystem} - onMsgDataLoaded={(data: MsgDataType, valid: boolean) => { - onMsgDataLoaded(data, msgId, msgValue || msg || '', valid); + onMsgDataLoaded={(data: MsgDataType, valid: boolean, isRefresh) => { + onMsgDataLoaded(data, msgId, msgValue || msg || '', valid, isRefresh); }} onUpdateMessageScroll={updateMessageContainerScroll} onSendMsg={onSendMsg} diff --git a/webapp/packages/chat-sdk/src/Chat/components/Text.tsx b/webapp/packages/chat-sdk/src/Chat/components/Text.tsx index 6e66daa72..449f45399 100644 --- a/webapp/packages/chat-sdk/src/Chat/components/Text.tsx +++ b/webapp/packages/chat-sdk/src/Chat/components/Text.tsx @@ -5,14 +5,16 @@ import LeftAvatar from './CopilotAvatar'; import Message from './Message'; import styles from './style.module.less'; import { userAvatarUrl } from '../../common/env'; +import IconFont from '../../components/IconFont'; type Props = { position: 'left' | 'right'; data: any; quote?: string; + anonymousUser?: boolean; }; -const Text: React.FC = ({ position, data, quote }) => { +const Text: React.FC = ({ position, data, quote, anonymousUser }) => { const textWrapperClass = classNames(styles.textWrapper, { [styles.rightTextWrapper]: position === 'right', }); @@ -25,7 +27,13 @@ const Text: React.FC = ({ position, data, quote }) => {
{data}
{!isMobile && position === 'right' && rightAvatarUrl && ( - + } + className={styles.rightAvatar} + /> )}
); diff --git a/webapp/packages/chat-sdk/src/Chat/index.tsx b/webapp/packages/chat-sdk/src/Chat/index.tsx index 41c95a1c5..5da4b36ff 100644 --- a/webapp/packages/chat-sdk/src/Chat/index.tsx +++ b/webapp/packages/chat-sdk/src/Chat/index.tsx @@ -20,6 +20,8 @@ import AgentList from './AgentList'; import MobileAgents from './MobileAgents'; import { HistoryMsgItemType, MsgDataType, SendMsgParamsType } from '../common/type'; import { getHistoryMsg } from '../service'; +import ShowCase from '../ShowCase'; +import { Modal } from 'antd'; type Props = { token?: string; @@ -30,7 +32,6 @@ type Props = { isDeveloper?: boolean; integrateSystem?: string; isCopilot?: boolean; - apiUrl?: string; onCurrentAgentChange?: (agent?: AgentType) => void; onReportMsgEvent?: (msg: string, valid: boolean) => void; }; @@ -45,7 +46,6 @@ const Chat: ForwardRefRenderFunction = ( isDeveloper, integrateSystem, isCopilot, - apiUrl, onCurrentAgentChange, onReportMsgEvent, }, @@ -64,6 +64,7 @@ const Chat: ForwardRefRenderFunction = ( const [currentAgent, setCurrentAgent] = useState(); const [mobileAgentsVisible, setMobileAgentsVisible] = useState(false); const [agentListVisible, setAgentListVisible] = useState(true); + const [showCaseVisible, setShowCaseVisible] = useState(false); const conversationRef = useRef(); const chatFooterRef = useRef(); @@ -120,12 +121,6 @@ const Chat: ForwardRefRenderFunction = ( } }, [token]); - useEffect(() => { - if (apiUrl) { - localStorage.setItem('SUPERSONIC_CHAT_API_URL', apiUrl); - } - }, [apiUrl]); - useEffect(() => { if (chatVisible) { inputFocus(); @@ -300,7 +295,8 @@ const Chat: ForwardRefRenderFunction = ( data: MsgDataType, questionId: string | number, question: string, - valid: boolean + valid: boolean, + isRefresh?: boolean ) => { onReportMsgEvent?.(question, valid); if (!isMobile) { @@ -315,7 +311,9 @@ const Chat: ForwardRefRenderFunction = ( msg.msgData = data; setMessageList(msgs); } - updateMessageContainerScroll(`${questionId}`); + if (!isRefresh) { + updateMessageContainerScroll(`${questionId}`); + } }; const onToggleHistoryVisible = () => { @@ -404,6 +402,9 @@ const Chat: ForwardRefRenderFunction = ( setAgentListVisible(!agentListVisible); } }} + onOpenShowcase={() => { + setShowCaseVisible(!showCaseVisible); + }} ref={chatFooterRef} /> )} @@ -419,6 +420,23 @@ const Chat: ForwardRefRenderFunction = ( onCloseConversation={onCloseConversation} ref={conversationRef} /> + {currentAgent && ( + { + setShowCaseVisible(false); + }} + > +
+ +
+
+ )}
void; +}; + +const ShowCase: React.FC = ({ agentId, onSendMsg }) => { + const [showCaseMap, setShowCaseMap] = useState({}); + const [loading, setLoading] = useState(false); + + const updateData = async (pageNo: number) => { + if (pageNo === 1) { + setLoading(true); + } + const res = await queryShowCase(agentId, pageNo, 20); + if (pageNo === 1) { + setLoading(false); + } + setShowCaseMap( + pageNo === 1 ? res.data.showCaseMap : { ...showCaseMap, ...res.data.showCaseMap } + ); + }; + + useEffect(() => { + if (agentId) { + updateData(1); + } + }, [agentId]); + + return ( + +
+ {Object.keys(showCaseMap || {}).map(key => { + const showCaseItem = showCaseMap?.[key] || []; + return ( +
+ {showCaseItem + .filter((chatItem: HistoryMsgItemType) => !!chatItem.queryResult) + .slice(0, 10) + .map((chatItem: HistoryMsgItemType) => { + return ( +
+ + +
+ ); + })} +
+ ); + })} +
+
+ ); +}; + +export default ShowCase; diff --git a/webapp/packages/chat-sdk/src/ShowCase/service.ts b/webapp/packages/chat-sdk/src/ShowCase/service.ts new file mode 100644 index 000000000..a94ff5677 --- /dev/null +++ b/webapp/packages/chat-sdk/src/ShowCase/service.ts @@ -0,0 +1,12 @@ +import axios from '../service/axiosInstance'; +import { isMobile } from '../utils/utils'; +import { ShowCaseType } from './type'; + +const prefix = isMobile ? '/openapi' : '/api'; + +export function queryShowCase(agentId: number, current: number, pageSize: number) { + return axios.post( + `${prefix}/chat/manage/queryShowCase?agentId=${agentId}`, + { current, pageSize } + ); +} diff --git a/webapp/packages/chat-sdk/src/ShowCase/style.module.less b/webapp/packages/chat-sdk/src/ShowCase/style.module.less new file mode 100644 index 000000000..93988dc67 --- /dev/null +++ b/webapp/packages/chat-sdk/src/ShowCase/style.module.less @@ -0,0 +1,27 @@ +.showCase { + column-count: 2; + column-gap: 20px; + height: 100%; + min-height: 400px; + overflow-y: auto; + + .showCaseItem { + display: flex; + flex-direction: column; + 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 { + display: flex; + flex-direction: column; + row-gap: 12px; + } + } +} diff --git a/webapp/packages/chat-sdk/src/ShowCase/type.ts b/webapp/packages/chat-sdk/src/ShowCase/type.ts new file mode 100644 index 000000000..8313a16e5 --- /dev/null +++ b/webapp/packages/chat-sdk/src/ShowCase/type.ts @@ -0,0 +1,9 @@ +import { HistoryMsgItemType } from "../common/type"; + +export type ShowCaseMapType = Record; + +export type ShowCaseType = { + showCaseMap: ShowCaseMapType, + current: number, + pageSize: number, +} \ No newline at end of file diff --git a/webapp/packages/chat-sdk/src/common/type.ts b/webapp/packages/chat-sdk/src/common/type.ts index c78fad83f..aacb7fd86 100644 --- a/webapp/packages/chat-sdk/src/common/type.ts +++ b/webapp/packages/chat-sdk/src/common/type.ts @@ -71,7 +71,7 @@ export type EntityDimensionType = { } export type SqlInfoType = { - llmParseSql: string; + s2QL: string; logicSql: string; querySql: string; } diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx index 860e7e9a6..e76403945 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/FilterItem.tsx @@ -13,6 +13,7 @@ type Props = { chatContext: ChatContextType; agentId?: number; entityAlias?: string; + integrateSystem?: string; onFiltersChange: (filters: FilterItemType[]) => void; onSwitchEntity: (entityId: string) => void; }; @@ -24,6 +25,7 @@ const FilterItem: React.FC = ({ chatContext, agentId, entityAlias, + integrateSystem, onFiltersChange, onSwitchEntity, }) => { @@ -50,7 +52,11 @@ const FilterItem: React.FC = ({ }; useEffect(() => { - if ((typeof filter.value === 'string' || isArray(filter.value)) && options.length === 0) { + if ( + (typeof filter.value === 'string' || isArray(filter.value)) && + options.length === 0 && + integrateSystem !== 'showcase' + ) { initData(); } }, []); @@ -148,17 +154,24 @@ const FilterItem: React.FC = ({ onSearch={debounceFetcher} notFoundContent={loading ? : null} onChange={onChange} - mode={isArray(filter.value) ? 'multiple' : undefined} + mode="multiple" showSearch + allowClear /> ) : entityAlias && ['歌曲', '艺人'].includes(entityAlias) && filter.bizName?.includes('_id') ? ( - + <> + + + (如未匹配到相关{entityAlias},可点击{entityAlias === '艺人' ? '歌手' : entityAlias} + ID切换) + + ) : ( {filter.value} )} diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx index 17a2e5023..7760c0470 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/ParseTip.tsx @@ -18,6 +18,7 @@ type Props = { dimensionFilters: FilterItemType[]; dateInfo: DateInfoType; entityInfo: EntityInfoType; + integrateSystem?: string; onSelectParseInfo: (parseInfo: ChatContextType) => void; onSwitchEntity: (entityId: string) => void; onFiltersChange: (filters: FilterItemType[]) => void; @@ -35,6 +36,7 @@ const ParseTip: React.FC = ({ dimensionFilters, dateInfo, entityInfo, + integrateSystem, onSelectParseInfo, onSwitchEntity, onFiltersChange, @@ -115,14 +117,14 @@ const ParseTip: React.FC = ({ return (
- {!!agentType && queryMode !== 'DSL' ? ( + {!!agentType && queryMode !== 'LLM_S2QL' ? (
将由{agentType === 'plugin' ? '插件' : '内置'}工具 {agentName}来解答
) : ( <> - {(queryMode?.includes('ENTITY') || queryMode === 'DSL') && + {(queryMode?.includes('ENTITY') || queryMode === 'LLM_S2QL') && typeof entityId === 'string' && !!entityAlias && !!entityName ? ( @@ -144,12 +146,14 @@ const ParseTip: React.FC = ({
{metric.name}
)} - {['METRIC_GROUPBY', 'METRIC_ORDERBY', 'ENTITY_DETAIL', 'DSL'].includes(queryMode!) && + {['METRIC_GROUPBY', 'METRIC_ORDERBY', 'ENTITY_DETAIL', 'LLM_S2QL'].includes( + queryMode! + ) && fields && fields.length > 0 && (
- {queryMode === 'DSL' + {queryMode === 'LLM_S2QL' ? nativeQuery ? '查询字段' : '下钻维度' @@ -178,12 +182,14 @@ const ParseTip: React.FC = ({
{dimension.value}
))} - {queryMode === 'METRIC_ORDERBY' && aggType && aggType !== 'NONE' && ( -
-
聚合方式:
-
{AGG_TYPE_MAP[aggType]}
-
- )} + {(queryMode === 'METRIC_ORDERBY' || queryMode === 'METRIC_MODEL') && + aggType && + aggType !== 'NONE' && ( +
+
聚合方式:
+
{AGG_TYPE_MAP[aggType]}
+
+ )} )}
@@ -218,6 +224,7 @@ const ParseTip: React.FC = ({ chatContext={currentParseInfo!} entityAlias={entityAlias} agentId={agentId} + integrateSystem={integrateSystem} onFiltersChange={onFiltersChange} onSwitchEntity={onSwitchEntity} key={filter.name} @@ -240,11 +247,6 @@ const ParseTip: React.FC = ({
{getTipNode()} {getFiltersNode()} - {(!type || queryMode === 'DSL') && entityAlias && entityAlias !== '厂牌' && entityName && ( -
- (如未匹配到相关{entityAlias},可点击{entityAlias === '艺人' ? '歌手' : entityAlias}ID切换) -
- )}
); diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx index 9686e570a..b93a7b5e7 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx @@ -27,7 +27,7 @@ const SqlItem: React.FC = ({ integrateSystem, sqlInfo }) => { setSqlType(''); }; - if (!sqlInfo.llmParseSql && !sqlInfo.logicSql && !sqlInfo.querySql) { + if (!sqlInfo.s2QL && !sqlInfo.logicSql && !sqlInfo.querySql) { return null; } @@ -44,13 +44,13 @@ const SqlItem: React.FC = ({ integrateSystem, sqlInfo }) => { )}
- {sqlInfo.llmParseSql && ( + {sqlInfo.s2QL && (
{ - setSqlType(sqlType === 'llmParseSql' ? '' : 'llmParseSql'); + setSqlType(sqlType === 's2QL' ? '' : 's2QL'); }} > LLM解析SQL diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx index 49865fdaa..6596f2c1a 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/index.tsx @@ -25,6 +25,7 @@ type Props = { conversationId?: number; modelId?: number; agentId?: number; + score?: number; filter?: any[]; isLastMessage?: boolean; msgData?: MsgDataType; @@ -33,7 +34,7 @@ type Props = { integrateSystem?: string; executeItemNode?: React.ReactNode; renderCustomExecuteNode?: boolean; - onMsgDataLoaded?: (data: MsgDataType, valid: boolean) => void; + onMsgDataLoaded?: (data: MsgDataType, valid: boolean, isRefresh?: boolean) => void; onUpdateMessageScroll?: () => void; onSendMsg?: (msg: string) => void; }; @@ -43,6 +44,7 @@ const ChatItem: React.FC = ({ conversationId, modelId, agentId, + score, filter, isLastMessage, triggerResize, @@ -68,8 +70,6 @@ const ChatItem: React.FC = ({ const [dateInfo, setDateInfo] = useState({} as DateInfoType); const [entityInfo, setEntityInfo] = useState({} as EntityInfoType); - // const [chartIndex, setChartIndex] = useState(0); - const prefixCls = `${PREFIX_CLS}-item`; const updateData = (res: Result) => { @@ -208,9 +208,7 @@ const ChatItem: React.FC = ({ const resChatContext = res.data?.chatContext; const contextValue = { ...(resChatContext || chatContextValue), queryId }; const dataValue = { ...res.data, chatContext: contextValue }; - if (onMsgDataLoaded) { - onMsgDataLoaded(dataValue, true); - } + onMsgDataLoaded?.(dataValue, true, true); setData(dataValue); setParseInfo(contextValue); } @@ -230,7 +228,6 @@ const ChatItem: React.FC = ({ } else { getEntityInfo(parseInfoValue); } - onUpdateMessageScroll?.(); }; const onSelectQuestion = (question: SimilarQuestionType) => { @@ -261,6 +258,7 @@ const ChatItem: React.FC = ({ dimensionFilters={dimensionFilters} dateInfo={dateInfo} entityInfo={entityInfo} + integrateSystem={integrateSystem} onSelectParseInfo={onSelectParseInfo} onSwitchEntity={onSwitchEntity} onFiltersChange={onFiltersChange} @@ -294,11 +292,11 @@ const ChatItem: React.FC = ({ /> )}
- {!isMetricCard && data && ( + {integrateSystem !== 'showcase' && ( )}
diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/style.less b/webapp/packages/chat-sdk/src/components/ChatItem/style.less index a2992ec88..1e22e650f 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/style.less +++ b/webapp/packages/chat-sdk/src/components/ChatItem/style.less @@ -164,15 +164,6 @@ line-height: 20px; } - &-switch-entity-tip { - display: flex; - align-items: center; - column-gap: 6px; - color: var(--text-color-fourth); - font-size: 13px; - font-weight: normal; - } - &-switch-entity { cursor: pointer; } @@ -372,6 +363,16 @@ min-width: 100px; } + &-switch-entity-tip { + display: flex; + align-items: center; + column-gap: 6px; + margin-left: 4px; + color: var(--text-color-fourth); + font-size: 13px; + font-weight: normal; + } + .ant-select-selector, .ant-input-number-input { background-color: #f5f8fb !important; border-color: #ececec !important; diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/index.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/index.tsx index f5808029c..6795c85bb 100644 --- a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/index.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/index.tsx @@ -28,11 +28,7 @@ const MetricCard: React.FC = ({ data, loading, onApplyAuth }) => { const prefixCls = `${PREFIX_CLS}-metric-card`; const matricCardClass = classNames(prefixCls, { - [`${PREFIX_CLS}-metric-card-dsl`]: queryMode === 'DSL', - }); - - const indicatorClass = classNames(`${prefixCls}-indicator`, { - [`${prefixCls}-indicator-period-compare`]: metricInfos?.length > 0, + [`${PREFIX_CLS}-metric-card-dsl`]: queryMode === 'LLM_S2QL', }); const [isNumber, setIsNumber] = useState(false); @@ -50,7 +46,7 @@ const MetricCard: React.FC = ({ data, loading, onApplyAuth }) => { )} -
+
{indicatorColumn && !indicatorColumn?.authorized ? ( ) : ( diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/style.less b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/style.less index 111b74afe..98dca8df8 100644 --- a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/style.less +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricCard/style.less @@ -55,12 +55,8 @@ &-indicator { display: flex; flex-direction: column; - align-items: center; - justify-content: flex-start; - } - - &-indicator-period-compare { align-items: flex-start; + justify-content: flex-start; } &-date-range { @@ -90,6 +86,7 @@ column-gap: 40px; font-size: 13px; overflow-x: auto; + margin-bottom: 12px; } &-period-compare-item { diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MetricTrendChart.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MetricTrendChart.tsx index a48b7cee9..2547c9e0f 100644 --- a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MetricTrendChart.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MetricTrendChart.tsx @@ -13,6 +13,7 @@ import moment from 'moment'; import { ColumnType } from '../../../common/type'; import NoPermissionChart from '../NoPermissionChart'; import classNames from 'classnames'; +import { isArray } from 'lodash'; type Props = { model?: string; @@ -83,7 +84,9 @@ const MetricTrendChart: React.FC = ({ }); const xData = groupData[sortedGroupKeys[0]]?.map((item: any) => { - const date = `${item[dateColumnName]}`; + const date = isArray(item[dateColumnName]) + ? item[dateColumnName].join('-') + : `${item[dateColumnName]}`; return date.length === 10 ? moment(date).format('MM-DD') : date; }); diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.tsx new file mode 100644 index 000000000..42a6c035f --- /dev/null +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.tsx @@ -0,0 +1,148 @@ +import { CHART_SECONDARY_COLOR, CLS_PREFIX, THEME_COLOR_LIST } from '../../../common/constants'; +import { getFormattedValue } from '../../../utils/utils'; +import type { ECharts } from 'echarts'; +import * as echarts from 'echarts'; +import React, { useEffect, useRef, useState } from 'react'; +import moment from 'moment'; +import { ColumnType } from '../../../common/type'; +import { isArray } from 'lodash'; + +type Props = { + dateColumnName: string; + metricFields: ColumnType[]; + resultList: any[]; + triggerResize?: boolean; +}; + +const MultiMetricsTrendChart: React.FC = ({ + dateColumnName, + metricFields, + resultList, + triggerResize, +}) => { + const chartRef = useRef(); + const [instance, setInstance] = useState(); + + const renderChart = () => { + let instanceObj: any; + if (!instance) { + instanceObj = echarts.init(chartRef.current); + setInstance(instanceObj); + } else { + instanceObj = instance; + instanceObj.clear(); + } + + const xData = resultList?.map((item: any) => { + const date = isArray(item[dateColumnName]) + ? item[dateColumnName].join('-') + : `${item[dateColumnName]}`; + return date.length === 10 ? moment(date).format('MM-DD') : date; + }); + + instanceObj.setOption({ + legend: { + left: 0, + top: 0, + icon: 'rect', + itemWidth: 15, + itemHeight: 5, + type: 'scroll', + }, + xAxis: { + type: 'category', + axisTick: { + alignWithLabel: true, + lineStyle: { + color: CHART_SECONDARY_COLOR, + }, + }, + axisLine: { + lineStyle: { + color: CHART_SECONDARY_COLOR, + }, + }, + axisLabel: { + showMaxLabel: true, + color: '#999', + }, + data: xData, + }, + yAxis: { + type: 'value', + splitLine: { + lineStyle: { + opacity: 0.3, + }, + }, + axisLabel: { + formatter: function (value: any) { + return value === 0 ? 0 : getFormattedValue(value); + }, + }, + }, + tooltip: { + trigger: 'axis', + formatter: function (params: any[]) { + const param = params[0]; + const valueLabels = params + .sort((a, b) => b.value - a.value) + .map( + (item: any) => + `
${ + item.marker + } ${ + item.seriesName + }${ + item.value === '' ? '-' : getFormattedValue(item.value) + }
` + ) + .join(''); + return `${param.name}
${valueLabels}`; + }, + }, + grid: { + left: '1%', + right: '4%', + bottom: '3%', + top: 45, + containLabel: true, + }, + series: metricFields.map((metricField, index) => { + return { + type: 'line', + name: metricField.name, + symbol: 'circle', + showSymbol: resultList.length === 1, + smooth: true, + data: resultList.map((item: any) => { + const value = item[metricField.nameEn]; + return (metricField.dataFormatType === 'percent' || + metricField.dataFormatType === 'decimal') && + metricField.dataFormat?.needMultiply100 + ? value * 100 + : value; + }), + color: THEME_COLOR_LIST[index], + }; + }), + }); + instanceObj.resize(); + }; + + useEffect(() => { + renderChart(); + }, [resultList]); + + useEffect(() => { + if (triggerResize && instance) { + instance.resize(); + } + }, [triggerResize]); + + const prefixCls = `${CLS_PREFIX}-metric-trend`; + + return
; +}; + +export default MultiMetricsTrendChart; diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/index.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/index.tsx index 22d5d2715..b692da89f 100644 --- a/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/index.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/MetricTrend/index.tsx @@ -1,11 +1,12 @@ import { CLS_PREFIX } from '../../../common/constants'; -import { FieldType, MsgDataType } from '../../../common/type'; +import { DrillDownDimensionType, FieldType, MsgDataType } from '../../../common/type'; import { isMobile } from '../../../utils/utils'; import MetricTrendChart from './MetricTrendChart'; import { Spin } from 'antd'; import Table from '../Table'; import MetricInfo from './MetricInfo'; import DateOptions from '../DateOptions'; +import MultiMetricsTrendChart from './MultiMetricsTrendChart'; type Props = { data: MsgDataType; @@ -13,6 +14,7 @@ type Props = { triggerResize?: boolean; loading: boolean; activeMetricField?: FieldType; + drillDownDimension?: DrillDownDimensionType; currentDateOption?: number; onApplyAuth?: (model: string) => void; onSelectDateOption: (value: number) => void; @@ -24,6 +26,7 @@ const MetricTrend: React.FC = ({ triggerResize, loading, activeMetricField, + drillDownDimension, currentDateOption, onApplyAuth, onSelectDateOption, @@ -36,6 +39,7 @@ const MetricTrend: React.FC = ({ const dateColumnName = dateField?.nameEn || ''; const categoryColumnName = queryColumns?.find((column: any) => column.showType === 'CATEGORY')?.nameEn || ''; + const metricFields = queryColumns?.filter((column: any) => column.showType === 'NUMBER'); const currentMetricField = queryColumns?.find((column: any) => column.showType === 'NUMBER'); @@ -48,19 +52,23 @@ const MetricTrend: React.FC = ({ return (
-
-
- {activeMetricField?.name} + {metricFields?.length === 1 && ( +
+
+ {activeMetricField?.name} +
-
+ )}
- {!isMobile && aggregateInfo?.metricInfos?.length > 0 && ( - - )} + {!isMobile && + aggregateInfo?.metricInfos?.length > 0 && + drillDownDimension === undefined && ( + + )} = ({ /> {queryResults?.length === 1 || chartIndex % 2 === 1 ? ( + ) : metricFields.length > 1 ? ( + ) : ( = ({ queryId, data, chartIndex, triggerResize }) const metricFields = columns.filter(item => item.showType === 'NUMBER'); const isDslMetricCard = - queryMode === 'DSL' && singleData && metricFields.length === 1 && columns.length === 1; + queryMode === 'LLM_S2QL' && singleData && metricFields.length === 1 && columns.length === 1; - const isMetricCard = - (queryMode.includes('METRIC') || isDslMetricCard) && - (singleData || chatContext?.dateInfo?.startDate === chatContext?.dateInfo?.endDate); + const isMetricCard = (queryMode.includes('METRIC') || isDslMetricCard) && singleData; const isText = columns.length === 1 && @@ -95,24 +93,27 @@ const ChatMsg: React.FC = ({ queryId, data, chartIndex, triggerResize }) if (isTable) { return
; } - if (dateField && metricFields.length > 0) { - if (!dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn])) { - return ( - - ); - } + if ( + dateField && + metricFields.length > 0 && + !dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn]) + ) { + return ( + + ); } if (categoryField?.length > 0 && metricFields?.length > 0) { return ( @@ -209,7 +210,11 @@ const ChatMsg: React.FC = ({ queryId, data, chartIndex, triggerResize })
{getMsgContent()} {(isMultipleMetric || existDrillDownDimension) && ( -
+
{isMultipleMetric && ( = ({ queryId, data, chartIndex, triggerResize }) {existDrillDownDimension && ( = ({ modelId, + metricId, drillDownDimension, isMetricCard, originDimensions, @@ -27,12 +31,10 @@ const DrillDownDimensions: React.FC = ({ }) => { const [dimensions, setDimensions] = useState([]); - const DEFAULT_DIMENSION_COUNT = isMetricCard ? 3 : 5; - const prefixCls = `${CLS_PREFIX}-drill-down-dimensions`; const initData = async () => { - const res = await queryDrillDownDimensions(modelId); + const res = await queryDrillDownDimensions(modelId, metricId); setDimensions( res.data.dimensions .filter( diff --git a/webapp/packages/chat-sdk/src/components/DrillDownDimensions/style.less b/webapp/packages/chat-sdk/src/components/DrillDownDimensions/style.less index 31c9796cb..fbf25fb6f 100644 --- a/webapp/packages/chat-sdk/src/components/DrillDownDimensions/style.less +++ b/webapp/packages/chat-sdk/src/components/DrillDownDimensions/style.less @@ -5,7 +5,6 @@ .@{drill-down-dimensions-prefix-cls} { display: flex; flex-direction: column; - margin-top: 2px; &-section { width: 100%; @@ -13,7 +12,6 @@ align-items: center; flex-wrap: wrap; column-gap: 6px; - margin-top: 6px; } &-metric-card { diff --git a/webapp/packages/chat-sdk/src/components/IconFont/index.tsx b/webapp/packages/chat-sdk/src/components/IconFont/index.tsx index 97fc9e303..e1b7e9c7e 100644 --- a/webapp/packages/chat-sdk/src/components/IconFont/index.tsx +++ b/webapp/packages/chat-sdk/src/components/IconFont/index.tsx @@ -1,7 +1,7 @@ import { createFromIconfontCN } from '@ant-design/icons'; const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4120566_46xw04fpzii.js', + scriptUrl: '//at.alicdn.com/t/c/font_4120566_2vn019wsui6.js', }); export default IconFont; diff --git a/webapp/packages/chat-sdk/src/components/MetricOptions/style.less b/webapp/packages/chat-sdk/src/components/MetricOptions/style.less index 74373f239..ff949afd3 100644 --- a/webapp/packages/chat-sdk/src/components/MetricOptions/style.less +++ b/webapp/packages/chat-sdk/src/components/MetricOptions/style.less @@ -12,8 +12,6 @@ align-items: center; flex-wrap: wrap; column-gap: 6px; - margin-top: 8px; - margin-bottom: 4px; } &-metric-card { diff --git a/webapp/packages/chat-sdk/src/components/Tools/index.tsx b/webapp/packages/chat-sdk/src/components/Tools/index.tsx index b8d86ec0e..562635c91 100644 --- a/webapp/packages/chat-sdk/src/components/Tools/index.tsx +++ b/webapp/packages/chat-sdk/src/components/Tools/index.tsx @@ -35,7 +35,7 @@ const Tools: React.FC = ({ queryId, scoreValue, isLastMessage }) => { return (
- {!isMobile && isLastMessage && ( + {!isMobile && (
这个回答正确吗?
diff --git a/webapp/packages/chat-sdk/src/index.tsx b/webapp/packages/chat-sdk/src/index.tsx index 92297d7c9..e4e126b30 100644 --- a/webapp/packages/chat-sdk/src/index.tsx +++ b/webapp/packages/chat-sdk/src/index.tsx @@ -5,7 +5,7 @@ import './styles/index.less'; // import ChatDemo from './demo/ChatDemo'; // import CopilotDemo from './demo/CopilotDemo'; // const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); -// root.render(); +// root.render(); export { default as Chat } from './Chat'; @@ -15,6 +15,8 @@ export { default as ChatMsg } from './components/ChatMsg'; export { default as ChatItem } from './components/ChatItem'; +export { default as ShowCase } from './ShowCase'; + export type { SearchRecommendItem, FieldType, diff --git a/webapp/packages/chat-sdk/src/service/axiosInstance.ts b/webapp/packages/chat-sdk/src/service/axiosInstance.ts index 4cc350452..4ff558edd 100644 --- a/webapp/packages/chat-sdk/src/service/axiosInstance.ts +++ b/webapp/packages/chat-sdk/src/service/axiosInstance.ts @@ -5,7 +5,7 @@ import { getToken } from '../utils/utils'; // 创建axios实例 const axiosInstance: AxiosInstance = axios.create({ // 设置基本URL,所有请求都会使用这个URL作为前缀 - baseURL: localStorage.getItem('SUPERSONIC_CHAT_API_URL') || '', + baseURL: '', // 设置请求超时时间(毫秒) timeout: 120000, // 设置请求头 @@ -19,7 +19,6 @@ axiosInstance.interceptors.request.use( (config: any) => { const token = getToken(); if (token && config?.headers) { - // config.headers.Auth = `Bearer ${token}`; config.headers.Authorization = `Bearer ${token}`; } return config; diff --git a/webapp/packages/chat-sdk/src/service/index.ts b/webapp/packages/chat-sdk/src/service/index.ts index 710ae158d..ab2675285 100644 --- a/webapp/packages/chat-sdk/src/service/index.ts +++ b/webapp/packages/chat-sdk/src/service/index.ts @@ -77,8 +77,8 @@ export function updateQAFeedback(questionId: number, score: number) { return axios.post(`${prefix}/chat/manage/updateQAFeedback?id=${questionId}&score=${score}&feedback=`); } -export function queryDrillDownDimensions(modelId: number) { - return axios.get<{ dimensions: DrillDownDimensionType[] }>(`${prefix}/chat/recommend/metric/${modelId}`); +export function queryDrillDownDimensions(modelId: number, metricId?: number) { + return axios.get<{ dimensions: DrillDownDimensionType[] }>(`${prefix}/chat/recommend/metric/${modelId}${metricId ? `?metricId=${metricId}` : ''}`); } export function queryDimensionValues(modelId: number, bizName: string, agentId: number, elementID: number, value: string) { @@ -86,7 +86,7 @@ export function queryDimensionValues(modelId: number, bizName: string, agentId: } export function querySimilarQuestions(queryText: string, agentId?: number) { - return axios.get(`${prefix}/chat/manage/getSolvedQuery?queryText=${queryText}&agentId=${agentId}`); + return axios.get(`${prefix}/chat/manage/getSolvedQuery?queryText=${queryText}&agentId=${agentId || 0}`); } export function queryEntityInfo(queryId: number, parseId: number) { diff --git a/webapp/packages/supersonic-fe/src/pages/Agent/ToolModal.tsx b/webapp/packages/supersonic-fe/src/pages/Agent/ToolModal.tsx index 35c82a6b5..2fef089bb 100644 --- a/webapp/packages/supersonic-fe/src/pages/Agent/ToolModal.tsx +++ b/webapp/packages/supersonic-fe/src/pages/Agent/ToolModal.tsx @@ -113,7 +113,7 @@ const ToolModal: React.FC = ({ editTool, onSaveTool, onCancel }) => { - {(toolType === AgentToolTypeEnum.RULE || toolType === AgentToolTypeEnum.DSL) && ( + {(toolType === AgentToolTypeEnum.RULE || toolType === AgentToolTypeEnum.LLM_S2QL) && (