[feature](weaapp) add agent

This commit is contained in:
williamhliu
2023-08-20 18:17:00 +08:00
parent c93e60ced7
commit aa218898ff
40 changed files with 1928 additions and 316 deletions

View File

@@ -1,3 +1,4 @@
import { Spin } from 'antd';
import { PREFIX_CLS } from '../../common/constants';
import { MsgDataType } from '../../common/type';
import ChatMsg from '../ChatMsg';
@@ -8,6 +9,7 @@ import Typing from './Typing';
type Props = {
question: string;
executeLoading: boolean;
entitySwitchLoading: boolean;
chartIndex: number;
executeTip?: string;
data?: MsgDataType;
@@ -21,6 +23,7 @@ type Props = {
const ExecuteItem: React.FC<Props> = ({
question,
executeLoading,
entitySwitchLoading,
chartIndex,
executeTip,
data,
@@ -50,13 +53,15 @@ const ExecuteItem: React.FC<Props> = ({
return (
<div className={`${prefixCls}-msg-content`}>
<ChatMsg
question={question}
data={data}
chartIndex={chartIndex}
isMobileMode={isMobileMode}
triggerResize={triggerResize}
/>
<Spin spinning={entitySwitchLoading}>
<ChatMsg
question={question}
data={data}
chartIndex={chartIndex}
isMobileMode={isMobileMode}
triggerResize={triggerResize}
/>
</Spin>
{!isMetricCard && (
<Tools
data={data}

View File

@@ -76,17 +76,7 @@ const ParseTip: React.FC<Props> = ({
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
const entityName = elementMatches?.find(item => item.element?.type === 'ID')?.element.name;
const pluginName = properties?.CONTEXT?.plugin?.name;
const modeName = pluginName
? '调插件'
: queryMode.includes('METRIC')
? '算指标'
: queryMode === 'ENTITY_DETAIL'
? '查明细'
: queryMode === 'ENTITY_LIST_FILTER'
? '做圈选'
: '';
const { type: agentType, name: agentName } = properties || {};
const fields =
queryMode === 'ENTITY_DETAIL' ? dimensionItems?.concat(metrics || []) : dimensionItems;
@@ -101,11 +91,10 @@ const ParseTip: React.FC<Props> = ({
}}
>
{index !== undefined && <div>{index + 1}.</div>}
{!pluginName && isOptions && <div className={`${prefixCls}-mode-name`}>{modeName}</div>}
{!!pluginName ? (
{!!agentType ? (
<div className={`${prefixCls}-tip-item`}>
<span className={itemValueClass}>{pluginName}</span>
{agentType === 'plugin' ? '插件' : '内置'}
<span className={itemValueClass}>{agentName}</span>
</div>
) : (
<>
@@ -123,7 +112,7 @@ const ParseTip: React.FC<Props> = ({
<div className={itemValueClass}>{modelName}</div>
</div>
)}
{modeName === '算指标' && metric && (
{metric && (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}></div>
<div className={itemValueClass}>{metric.name}</div>
@@ -153,9 +142,13 @@ const ParseTip: React.FC<Props> = ({
</div>
</div>
)}
{['METRIC_FILTER', 'METRIC_ENTITY', 'ENTITY_DETAIL', 'ENTITY_LIST_FILTER'].includes(
queryMode
) &&
{[
'METRIC_FILTER',
'METRIC_ENTITY',
'ENTITY_DETAIL',
'ENTITY_LIST_FILTER',
'ENTITY_ID',
].includes(queryMode) &&
dimensionFilters &&
dimensionFilters?.length > 0 && (
<div className={`${prefixCls}-tip-item`}>
@@ -198,10 +191,10 @@ const ParseTip: React.FC<Props> = ({
</div>
);
} else {
const pluginName = parseInfoOptions[0]?.properties?.CONTEXT?.plugin?.name;
const agentType = parseInfoOptions[0]?.properties?.type;
tipNode = (
<div className={`${prefixCls}-tip`}>
<div>{!!pluginName ? '您的问题' : '您的问题解析为:'}</div>
<div>{!!agentType ? '您的问题' : '您的问题解析为:'}</div>
{getTipNode(parseInfoOptions[0])}
</div>
);

View File

@@ -5,11 +5,14 @@ import { PARSE_ERROR_TIP, PREFIX_CLS, SEARCH_EXCEPTION_TIP } from '../../common/
import IconFont from '../IconFont';
import ParseTip from './ParseTip';
import ExecuteItem from './ExecuteItem';
import { isMobile } from '../../utils/utils';
import classNames from 'classnames';
type Props = {
msg: string;
conversationId?: number;
modelId?: number;
agentId?: number;
filter?: any[];
isLastMessage?: boolean;
msgData?: MsgDataType;
@@ -24,6 +27,7 @@ const ChatItem: React.FC<Props> = ({
msg,
conversationId,
modelId,
agentId,
filter,
isLastMessage,
isMobileMode,
@@ -41,7 +45,7 @@ const ChatItem: React.FC<Props> = ({
const [executeLoading, setExecuteLoading] = useState(false);
const [executeTip, setExecuteTip] = useState('');
const [executeMode, setExecuteMode] = useState(false);
const [entitySwitching, setEntitySwitching] = useState(false);
const [entitySwitchLoading, setEntitySwitchLoading] = useState(false);
const [chartIndex, setChartIndex] = useState(0);
@@ -76,37 +80,42 @@ const ChatItem: React.FC<Props> = ({
) => {
setExecuteMode(true);
setExecuteLoading(true);
const { data } = await chatExecute(msg, conversationId!, parseInfoValue);
setExecuteLoading(false);
const valid = updateData(data);
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'))
try {
const { data } = await chatExecute(msg, conversationId!, parseInfoValue);
setExecuteLoading(false);
const valid = updateData(data);
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
);
}
onMsgDataLoaded(
{
...data.data,
chatContext: parseInfoValue,
parseOptions: parseOptions.length > 1 ? parseOptions.slice(1) : undefined,
},
valid
);
} catch (e) {
setExecuteLoading(false);
setExecuteTip(SEARCH_EXCEPTION_TIP);
}
};
const onSendMsg = async () => {
setParseLoading(true);
const { data: parseData } = await chatParse(msg, conversationId, modelId, filter);
const { data: parseData } = await chatParse(msg, conversationId, modelId, agentId, filter);
setParseLoading(false);
const { code, data } = parseData || {};
const { state, selectedParses } = data || {};
@@ -115,10 +124,9 @@ const ChatItem: React.FC<Props> = ({
state === ParseStateEnum.FAILED ||
selectedParses == null ||
selectedParses.length === 0 ||
(selectedParses.length === 1 &&
!selectedParses[0]?.modelName &&
!selectedParses[0]?.properties?.CONTEXT?.plugin?.name &&
selectedParses[0]?.queryMode !== 'WEB_PAGE')
(selectedParses.length > 0 &&
!selectedParses[0]?.properties?.type &&
!selectedParses[0]?.queryMode)
) {
setParseTip(PARSE_ERROR_TIP);
return;
@@ -146,9 +154,9 @@ const ChatItem: React.FC<Props> = ({
}, [msg, msgData]);
const onSwitchEntity = async (entityId: string) => {
setEntitySwitching(true);
setEntitySwitchLoading(true);
const res = await switchEntity(entityId, data?.chatContext?.modelId, conversationId || 0);
setEntitySwitching(false);
setEntitySwitchLoading(false);
setData(res.data.data);
};
@@ -164,11 +172,15 @@ const ChatItem: React.FC<Props> = ({
}
};
const contentClass = classNames(`${prefixCls}-content`, {
[`${prefixCls}-content-mobile`]: isMobile,
});
return (
<div className={prefixCls}>
<div className={`${prefixCls}-section`}>
<IconFont type="icon-zhinengsuanfa" className={`${prefixCls}-avatar`} />
<div className={`${prefixCls}-content`}>
{!isMobile && <IconFont type="icon-zhinengsuanfa" className={`${prefixCls}-avatar`} />}
<div className={contentClass}>
<ParseTip
parseLoading={parseLoading}
parseInfoOptions={parseOptions || parseInfoOptions.slice(0, 1)}
@@ -181,11 +193,12 @@ const ChatItem: React.FC<Props> = ({
</div>
{executeMode && data?.queryMode !== 'WEB_PAGE' && (
<div className={`${prefixCls}-section`}>
<IconFont type="icon-zhinengsuanfa" className={`${prefixCls}-avatar`} />
<div className={`${prefixCls}-content`}>
{!isMobile && <IconFont type="icon-zhinengsuanfa" className={`${prefixCls}-avatar`} />}
<div className={contentClass}>
<ExecuteItem
question={msg}
executeLoading={executeLoading}
entitySwitchLoading={entitySwitchLoading}
executeTip={executeTip}
chartIndex={chartIndex}
data={data}

View File

@@ -117,6 +117,10 @@
width: calc(100% - 50px);
}
&-content-mobile {
width: 100%;
}
&-metric-info-list {
margin-top: 30px;
display: flex;
@@ -136,7 +140,6 @@
&-typing-bubble {
width: fit-content;
// padding: 16px !important;
}
&-text-bubble {