mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-12 20:51:48 +00:00
Integrate Chat and Copilot into chat-sdk, and add SQL parse display (#166)
This commit is contained in:
@@ -8,13 +8,17 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^4.7.0",
|
"@ant-design/icons": "^4.7.0",
|
||||||
"@uiw/react-watermark": "^0.0.5",
|
"@uiw/react-watermark": "^0.0.5",
|
||||||
|
"ahooks": "^3.7.8",
|
||||||
"antd": "^5.5.2",
|
"antd": "^5.5.2",
|
||||||
"axios": "^1.4.0",
|
"axios": "^0.21.1",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"echarts": "^5.4.2",
|
"echarts": "^5.4.2",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
"react-spinners": "^0.13.8",
|
"react-spinners": "^0.13.8",
|
||||||
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
|
"sql-formatter": "^2.3.3",
|
||||||
"tslib": "^2.5.2"
|
"tslib": "^2.5.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -72,6 +76,7 @@
|
|||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"@types/jest": "^27.5.2",
|
"@types/jest": "^27.5.2",
|
||||||
|
"@types/lodash": "^4.14.198",
|
||||||
"@types/node": "^16.18.31",
|
"@types/node": "^16.18.31",
|
||||||
"@types/react": "^18.2.6",
|
"@types/react": "^18.2.6",
|
||||||
"@types/react-dom": "^18.2.4",
|
"@types/react-dom": "^18.2.4",
|
||||||
@@ -122,6 +127,7 @@
|
|||||||
"rollup-plugin-exclude-dependencies-from-bundle": "^1.1.23",
|
"rollup-plugin-exclude-dependencies-from-bundle": "^1.1.23",
|
||||||
"rollup-plugin-less": "^1.1.3",
|
"rollup-plugin-less": "^1.1.3",
|
||||||
"rollup-plugin-postcss": "^4.0.2",
|
"rollup-plugin-postcss": "^4.0.2",
|
||||||
|
"rollup-plugin-styles": "^4.0.0",
|
||||||
"rollup-plugin-typescript2": "^0.34.1",
|
"rollup-plugin-typescript2": "^0.34.1",
|
||||||
"sass-loader": "^12.3.0",
|
"sass-loader": "^12.3.0",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root" style="height: 100vh;"></div>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
If you open it directly in the browser, you will see an empty page.
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
@@ -6,20 +6,10 @@
|
|||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
"type": "image/x-icon"
|
"type": "image/x-icon"
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "logo192.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "192x192"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "logo512.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"theme_color": "#000000",
|
"theme_color": "#000000",
|
||||||
"background_color": "#ffffff"
|
"background_color": "#ffffff"
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
|
|||||||
import commonjs from '@rollup/plugin-commonjs'
|
import commonjs from '@rollup/plugin-commonjs'
|
||||||
import json from '@rollup/plugin-json'
|
import json from '@rollup/plugin-json'
|
||||||
import less from 'rollup-plugin-less'
|
import less from 'rollup-plugin-less'
|
||||||
|
import styles from "rollup-plugin-styles";
|
||||||
import postcss from 'rollup-plugin-postcss'
|
import postcss from 'rollup-plugin-postcss'
|
||||||
import cssnano from 'cssnano'
|
import cssnano from 'cssnano'
|
||||||
|
|
||||||
@@ -18,7 +19,12 @@ const config = {
|
|||||||
commonjs(),
|
commonjs(),
|
||||||
json(),
|
json(),
|
||||||
typescript({ tsconfigOverride: overrides }),
|
typescript({ tsconfigOverride: overrides }),
|
||||||
less({ output: 'dist/index.css' }),
|
styles({
|
||||||
|
// mode: ["extract"],
|
||||||
|
// modules: true,
|
||||||
|
autoModules: id => id.includes(".module."),
|
||||||
|
}),
|
||||||
|
// less({ output: 'dist/index.css' }),
|
||||||
// postcss({
|
// postcss({
|
||||||
// plugins: [
|
// plugins: [
|
||||||
// cssnano()
|
// cssnano()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import basicConfig from './rollup.config.mjs'
|
import basicConfig from './rollup.config.mjs'
|
||||||
import excludeDependenciesFromBundle from "rollup-plugin-exclude-dependencies-from-bundle"
|
import excludeDependenciesFromBundle from "rollup-plugin-exclude-dependencies-from-bundle"
|
||||||
|
import terser from '@rollup/plugin-terser'
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
...basicConfig,
|
...basicConfig,
|
||||||
@@ -12,6 +13,7 @@ const config = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
...basicConfig.plugins,
|
...basicConfig.plugins,
|
||||||
excludeDependenciesFromBundle(),
|
excludeDependenciesFromBundle(),
|
||||||
|
terser()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { PlusCircleOutlined } from '@ant-design/icons';
|
import { PlusCircleOutlined } from '@ant-design/icons';
|
||||||
import { AgentType } from '../type';
|
import { AgentType } from '../type';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import IconFont from '@/components/IconFont';
|
import IconFont from '../../components/IconFont';
|
||||||
import { AGENT_ICONS } from '../constants';
|
import { AGENT_ICONS } from '../constants';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import IconFont from '@/components/IconFont';
|
import IconFont from '../../components/IconFont';
|
||||||
import { getTextWidth, groupByColumn, isMobile } from '@/utils/utils';
|
import { getTextWidth, groupByColumn, isMobile } from '../../utils/utils';
|
||||||
import { AutoComplete, Select, Tag } from 'antd';
|
import { AutoComplete, Select, Tag } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
||||||
import type { ForwardRefRenderFunction } from 'react';
|
import type { ForwardRefRenderFunction } from 'react';
|
||||||
import { searchRecommend } from 'supersonic-chat-sdk';
|
import { SemanticTypeEnum, SEMANTIC_TYPE_MAP, HOLDER_TAG } from '../constants';
|
||||||
import { SemanticTypeEnum, SEMANTIC_TYPE_MAP } from '../constants';
|
|
||||||
import styles from './style.less';
|
|
||||||
import { AgentType, ModelType } from '../type';
|
import { AgentType, ModelType } from '../type';
|
||||||
|
import { searchRecommend } from '../../service';
|
||||||
|
import styles from './style.module.less';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
inputMsg: string;
|
inputMsg: string;
|
||||||
@@ -16,7 +16,7 @@ type Props = {
|
|||||||
currentAgent?: AgentType;
|
currentAgent?: AgentType;
|
||||||
agentList: AgentType[];
|
agentList: AgentType[];
|
||||||
onToggleHistoryVisible: () => void;
|
onToggleHistoryVisible: () => void;
|
||||||
onOpenMobileAgents: () => void;
|
onOpenAgents: () => void;
|
||||||
onInputMsgChange: (value: string) => void;
|
onInputMsgChange: (value: string) => void;
|
||||||
onSendMsg: (msg: string, modelId?: number) => void;
|
onSendMsg: (msg: string, modelId?: number) => void;
|
||||||
onAddConversation: (agent?: AgentType) => void;
|
onAddConversation: (agent?: AgentType) => void;
|
||||||
@@ -42,13 +42,13 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
currentAgent,
|
currentAgent,
|
||||||
agentList,
|
agentList,
|
||||||
onToggleHistoryVisible,
|
onToggleHistoryVisible,
|
||||||
onOpenMobileAgents,
|
onOpenAgents,
|
||||||
onInputMsgChange,
|
onInputMsgChange,
|
||||||
onSendMsg,
|
onSendMsg,
|
||||||
onAddConversation,
|
onAddConversation,
|
||||||
onSelectAgent,
|
onSelectAgent,
|
||||||
},
|
},
|
||||||
ref,
|
ref
|
||||||
) => {
|
) => {
|
||||||
const [modelOptions, setModelOptions] = useState<(ModelType | AgentType)[]>([]);
|
const [modelOptions, setModelOptions] = useState<(ModelType | AgentType)[]>([]);
|
||||||
const [stepOptions, setStepOptions] = useState<Record<string, any[]>>({});
|
const [stepOptions, setStepOptions] = useState<Record<string, any[]>>({});
|
||||||
@@ -99,7 +99,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
.reduce((result, key) => {
|
.reduce((result, key) => {
|
||||||
result[key] = data[key].slice(
|
result[key] = data[key].slice(
|
||||||
0,
|
0,
|
||||||
Object.keys(data).length > 2 ? 2 : Object.keys(data).length > 1 ? 3 : 6,
|
Object.keys(data).length > 2 ? 2 : Object.keys(data).length > 1 ? 3 : 6
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}, {})
|
}, {})
|
||||||
@@ -110,7 +110,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
let msgValue = msg;
|
let msgValue = msg;
|
||||||
let modelId: number | undefined;
|
let modelId: number | undefined;
|
||||||
if (msg?.[0] === '/') {
|
if (msg?.[0] === '/') {
|
||||||
const agent = agentList.find((item) => msg.includes(`/${item.name}`));
|
const agent = agentList.find(item => msg.includes(`/${item.name}`));
|
||||||
msgValue = agent ? msg.replace(`/${agent.name}`, '') : msg;
|
msgValue = agent ? msg.replace(`/${agent.name}`, '') : msg;
|
||||||
}
|
}
|
||||||
return { msgValue, modelId };
|
return { msgValue, modelId };
|
||||||
@@ -131,8 +131,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
if (fetchId !== fetchRef.current) {
|
if (fetchId !== fetchRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const recommends = msgValue ? res.data || [] : [];
|
||||||
const recommends = msgValue ? res.data.data || [] : [];
|
|
||||||
const stepOptionList = recommends.map((item: any) => item.subRecommend);
|
const stepOptionList = recommends.map((item: any) => item.subRecommend);
|
||||||
|
|
||||||
if (stepOptionList.length > 0 && stepOptionList.every((item: any) => item !== null)) {
|
if (stepOptionList.length > 0 && stepOptionList.every((item: any) => item !== null)) {
|
||||||
@@ -153,13 +152,11 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
setModelOptions(agentList);
|
setModelOptions(agentList);
|
||||||
setStepOptions({});
|
setStepOptions({});
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
setOpen(false);
|
if (modelOptions.length > 0) {
|
||||||
if (modelOptions.length > 0) {
|
setTimeout(() => {
|
||||||
setTimeout(() => {
|
setModelOptions([]);
|
||||||
setModelOptions([]);
|
}, 50);
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!isSelect) {
|
if (!isSelect) {
|
||||||
debounceGetWords(inputMsg, chatId, currentAgent);
|
debounceGetWords(inputMsg, chatId, currentAgent);
|
||||||
@@ -180,7 +177,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const autoCompleteDropdown = document.querySelector(
|
const autoCompleteDropdown = document.querySelector(
|
||||||
`.${styles.autoCompleteDropdown}`,
|
`.${styles.autoCompleteDropdown}`
|
||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
if (!autoCompleteDropdown) {
|
if (!autoCompleteDropdown) {
|
||||||
return;
|
return;
|
||||||
@@ -201,10 +198,10 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
result = result.concat(stepOptions[item]);
|
result = result.concat(stepOptions[item]);
|
||||||
return result;
|
return result;
|
||||||
}, [])
|
}, [])
|
||||||
.find((item) =>
|
.find(item =>
|
||||||
Object.keys(stepOptions).length === 1
|
Object.keys(stepOptions).length === 1
|
||||||
? item.recommend === value
|
? item.recommend === value
|
||||||
: `${item.modelName || ''}${item.recommend}` === value,
|
: `${item.modelName || ''}${item.recommend}` === value
|
||||||
);
|
);
|
||||||
if (option && isSelect) {
|
if (option && isSelect) {
|
||||||
onSendMsg(option.recommend, Object.keys(stepOptions).length > 1 ? option.modelId : undefined);
|
onSendMsg(option.recommend, Object.keys(stepOptions).length > 1 ? option.modelId : undefined);
|
||||||
@@ -220,16 +217,16 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
|
|
||||||
const onSelect = (value: string) => {
|
const onSelect = (value: string) => {
|
||||||
isSelect = true;
|
isSelect = true;
|
||||||
if (modelOptions.length === 0) {
|
if (modelOptions.length > 0) {
|
||||||
sendMsg(value);
|
const agent = agentList.find(item => value.includes(item.name));
|
||||||
} else {
|
|
||||||
const agent = agentList.find((item) => value.includes(item.name));
|
|
||||||
if (agent) {
|
if (agent) {
|
||||||
if (agent.id !== currentAgent?.id) {
|
if (agent.id !== currentAgent?.id) {
|
||||||
onSelectAgent(agent);
|
onSelectAgent(agent);
|
||||||
}
|
}
|
||||||
onInputMsgChange('');
|
onInputMsgChange('');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
onInputMsgChange(value.replace(HOLDER_TAG, ''));
|
||||||
}
|
}
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -241,7 +238,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
[styles.mobile]: isMobile,
|
[styles.mobile]: isMobile,
|
||||||
});
|
});
|
||||||
|
|
||||||
const modelOptionNodes = modelOptions.map((model) => {
|
const modelOptionNodes = modelOptions.map(model => {
|
||||||
return (
|
return (
|
||||||
<Option key={model.id} value={`/${model.name} `} className={styles.searchOption}>
|
<Option key={model.id} value={`/${model.name} `} className={styles.searchOption}>
|
||||||
{model.name}
|
{model.name}
|
||||||
@@ -249,22 +246,22 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const associateOptionNodes = Object.keys(stepOptions).map((key) => {
|
const associateOptionNodes = Object.keys(stepOptions).map(key => {
|
||||||
return (
|
return (
|
||||||
<OptGroup key={key} label={key}>
|
<OptGroup key={key} label={key}>
|
||||||
{stepOptions[key].map((option) => {
|
{stepOptions[key].map(option => {
|
||||||
let optionValue =
|
let optionValue =
|
||||||
Object.keys(stepOptions).length === 1
|
Object.keys(stepOptions).length === 1
|
||||||
? option.recommend
|
? option.recommend
|
||||||
: `${option.modelName || ''}${option.recommend}`;
|
: `${option.modelName || ''}${option.recommend}`;
|
||||||
if (inputMsg[0] === '/') {
|
if (inputMsg[0] === '/') {
|
||||||
const agent = agentList.find((item) => inputMsg.includes(item.name));
|
const agent = agentList.find(item => inputMsg.includes(item.name));
|
||||||
optionValue = agent ? `/${agent.name} ${option.recommend}` : optionValue;
|
optionValue = agent ? `/${agent.name} ${option.recommend}` : optionValue;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Option
|
<Option
|
||||||
key={`${option.recommend}${option.modelName ? `_${option.modelName}` : ''}`}
|
key={`${option.recommend}${option.modelName ? `_${option.modelName}` : ''}`}
|
||||||
value={optionValue}
|
value={`${optionValue}${HOLDER_TAG}`}
|
||||||
className={styles.searchOption}
|
className={styles.searchOption}
|
||||||
>
|
>
|
||||||
<div className={styles.optionContent}>
|
<div className={styles.optionContent}>
|
||||||
@@ -312,12 +309,10 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
<div>历史对话</div>
|
<div>历史对话</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isMobile && (
|
<div className={styles.toolItem} onClick={onOpenAgents}>
|
||||||
<div className={styles.toolItem} onClick={onOpenMobileAgents}>
|
<IconFont type="icon-zhinengzhuli" className={styles.toolIcon} />
|
||||||
<IconFont type="icon-zhinengzhuli" className={styles.toolIcon} />
|
<div>智能助理</div>
|
||||||
<div>智能助理</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.composer}>
|
<div className={styles.composer}>
|
||||||
<div className={styles.composerInputWrapper}>
|
<div className={styles.composerInputWrapper}>
|
||||||
@@ -332,25 +327,24 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
}}
|
}}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
autoFocus={!isMobile}
|
autoFocus={!isMobile}
|
||||||
backfill
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
id="chatInput"
|
id="chatInput"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={e => {
|
||||||
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
|
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
|
||||||
{
|
const chatInputEl: any = document.getElementById('chatInput');
|
||||||
const chatInputEl: any = document.getElementById('chatInput');
|
const agent = agentList.find(
|
||||||
if (!isSelect) {
|
item => chatInputEl.value[0] === '/' && chatInputEl.value.includes(item.name)
|
||||||
sendMsg(chatInputEl.value);
|
);
|
||||||
setOpen(false);
|
if (agent) {
|
||||||
} else {
|
if (agent.id !== currentAgent?.id) {
|
||||||
const agent = agentList.find((item) => chatInputEl.value.includes(item.name));
|
onSelectAgent(agent);
|
||||||
if (agent) {
|
|
||||||
if (agent.id !== currentAgent?.id) {
|
|
||||||
onSelectAgent(agent);
|
|
||||||
}
|
|
||||||
onInputMsgChange('');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
onInputMsgChange('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isSelect) {
|
||||||
|
sendMsg(chatInputEl.value);
|
||||||
|
setOpen(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -364,7 +358,8 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
|||||||
listHeight={500}
|
listHeight={500}
|
||||||
allowClear
|
allowClear
|
||||||
open={open}
|
open={open}
|
||||||
getPopupContainer={(triggerNode) => triggerNode.parentNode}
|
defaultActiveFirstOption={false}
|
||||||
|
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||||
>
|
>
|
||||||
{modelOptions.length > 0 ? modelOptionNodes : associateOptionNodes}
|
{modelOptions.length > 0 ? modelOptionNodes : associateOptionNodes}
|
||||||
</AutoComplete>
|
</AutoComplete>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
.ant-select-selection-search-input {
|
.ant-select-selection-search-input {
|
||||||
height: 40px !important;
|
height: 40px !important;
|
||||||
padding: 0 16px;
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-select-selection-search {
|
.ant-select-selection-search {
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-select-selection-placeholder {
|
.ant-select-selection-placeholder {
|
||||||
padding-left: 6px;
|
padding-left: 2px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,52 +6,32 @@ import {
|
|||||||
forwardRef,
|
forwardRef,
|
||||||
ForwardRefRenderFunction,
|
ForwardRefRenderFunction,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
|
memo,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useLocation } from 'umi';
|
|
||||||
import ConversationModal from '../components/ConversationModal';
|
import ConversationModal from '../components/ConversationModal';
|
||||||
import { deleteConversation, getAllConversations, saveConversation } from '../service';
|
import { deleteConversation, getAllConversations, saveConversation } from '../service';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
import { AgentType, ConversationDetailType, DefaultEntityType } from '../type';
|
import { AgentType, ConversationDetailType } from '../type';
|
||||||
import { DEFAULT_CONVERSATION_NAME } from '../constants';
|
import { DEFAULT_CONVERSATION_NAME } from '../constants';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { CloseOutlined, DeleteOutlined, SearchOutlined } from '@ant-design/icons';
|
import { CloseOutlined, DeleteOutlined, SearchOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
agentList?: AgentType[];
|
|
||||||
currentAgent?: AgentType;
|
currentAgent?: AgentType;
|
||||||
currentConversation?: ConversationDetailType;
|
currentConversation?: ConversationDetailType;
|
||||||
historyVisible?: boolean;
|
historyVisible?: boolean;
|
||||||
isCopilotMode?: boolean;
|
|
||||||
defaultEntityFilter?: DefaultEntityType;
|
|
||||||
triggerNewConversation?: boolean;
|
|
||||||
onNewConversationTriggered?: () => void;
|
|
||||||
onSelectConversation: (
|
onSelectConversation: (
|
||||||
conversation: ConversationDetailType,
|
conversation: ConversationDetailType,
|
||||||
name?: string,
|
sendMsgParams?: any,
|
||||||
modelId?: number,
|
isAdd?: boolean
|
||||||
entityId?: string,
|
|
||||||
agent?: AgentType,
|
|
||||||
) => void;
|
) => void;
|
||||||
onCloseConversation: () => void;
|
onCloseConversation: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Conversation: ForwardRefRenderFunction<any, Props> = (
|
const Conversation: ForwardRefRenderFunction<any, Props> = (
|
||||||
{
|
{ currentAgent, currentConversation, historyVisible, onSelectConversation, onCloseConversation },
|
||||||
agentList,
|
ref
|
||||||
currentAgent,
|
|
||||||
currentConversation,
|
|
||||||
historyVisible,
|
|
||||||
isCopilotMode,
|
|
||||||
defaultEntityFilter,
|
|
||||||
triggerNewConversation,
|
|
||||||
onNewConversationTriggered,
|
|
||||||
onSelectConversation,
|
|
||||||
onCloseConversation,
|
|
||||||
},
|
|
||||||
ref,
|
|
||||||
) => {
|
) => {
|
||||||
const location = useLocation();
|
|
||||||
const { q, cid, modelId, entityId } = (location as any).query;
|
|
||||||
const [conversations, setConversations] = useState<ConversationDetailType[]>([]);
|
const [conversations, setConversations] = useState<ConversationDetailType[]>([]);
|
||||||
const [editModalVisible, setEditModalVisible] = useState(false);
|
const [editModalVisible, setEditModalVisible] = useState(false);
|
||||||
const [editConversation, setEditConversation] = useState<ConversationDetailType>();
|
const [editConversation, setEditConversation] = useState<ConversationDetailType>();
|
||||||
@@ -62,8 +42,8 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
onAddConversation,
|
onAddConversation,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const updateData = async (agent?: AgentType) => {
|
const updateData = async (agentId?: number) => {
|
||||||
const { data } = await getAllConversations(agent?.id || currentAgent?.id);
|
const { data } = await getAllConversations(agentId || currentAgent!.id);
|
||||||
const conversationList = data || [];
|
const conversationList = data || [];
|
||||||
setConversations(conversationList.slice(0, 200));
|
setConversations(conversationList.slice(0, 200));
|
||||||
return conversationList;
|
return conversationList;
|
||||||
@@ -72,42 +52,26 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
const data = await updateData();
|
const data = await updateData();
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
const chatId = cid;
|
onSelectConversation(data[0]);
|
||||||
if (chatId) {
|
|
||||||
const conversation = data.find((item: any) => item.chatId === +chatId);
|
|
||||||
onSelectConversation(conversation || data[0]);
|
|
||||||
} else {
|
|
||||||
onSelectConversation(data[0]);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
onAddConversation();
|
onAddConversation();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (triggerNewConversation) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (q && cid === undefined && window.location.href.includes('/chat')) {
|
|
||||||
// onAddConversation({
|
|
||||||
// name: q,
|
|
||||||
// modelId: modelId ? +modelId : undefined,
|
|
||||||
// entityId,
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// initData();
|
|
||||||
// }
|
|
||||||
// }, [q]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentAgent && !triggerNewConversation) {
|
if (currentAgent) {
|
||||||
initData();
|
if (currentAgent.initialSendMsgParams) {
|
||||||
|
onAddConversation(currentAgent.initialSendMsgParams);
|
||||||
|
} else {
|
||||||
|
initData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [currentAgent]);
|
}, [currentAgent]);
|
||||||
|
|
||||||
const addConversation = async (name?: string, agent?: AgentType) => {
|
const addConversation = async (sendMsgParams?: any) => {
|
||||||
await saveConversation(name || DEFAULT_CONVERSATION_NAME, agent?.id || currentAgent!.id);
|
const agentId = sendMsgParams?.agentId || currentAgent!.id;
|
||||||
return updateData(agent);
|
await saveConversation(DEFAULT_CONVERSATION_NAME, agentId);
|
||||||
|
return updateData(agentId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteConversation = async (id: number) => {
|
const onDeleteConversation = async (id: number) => {
|
||||||
@@ -115,28 +79,10 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
initData();
|
initData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onAddConversation = async ({
|
const onAddConversation = async (sendMsgParams?: any) => {
|
||||||
name,
|
const data = await addConversation(sendMsgParams);
|
||||||
modelId,
|
|
||||||
entityId,
|
|
||||||
type,
|
|
||||||
agent,
|
|
||||||
}: {
|
|
||||||
name?: string;
|
|
||||||
modelId?: number;
|
|
||||||
entityId?: string;
|
|
||||||
type?: string;
|
|
||||||
agent?: AgentType;
|
|
||||||
} = {}) => {
|
|
||||||
const data = await addConversation(name, agent);
|
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
onSelectConversation(
|
onSelectConversation(data[0], sendMsgParams, true);
|
||||||
data[0],
|
|
||||||
type || name || DEFAULT_CONVERSATION_NAME,
|
|
||||||
modelId,
|
|
||||||
entityId,
|
|
||||||
agent,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,7 +97,6 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
|
|
||||||
const conversationClass = classNames(styles.conversation, {
|
const conversationClass = classNames(styles.conversation, {
|
||||||
[styles.historyVisible]: historyVisible,
|
[styles.historyVisible]: historyVisible,
|
||||||
[styles.copilotMode]: isCopilotMode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const convertTime = (date: string) => {
|
const convertTime = (date: string) => {
|
||||||
@@ -203,11 +148,11 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
<div className={styles.conversationList}>
|
<div className={styles.conversationList}>
|
||||||
{conversations
|
{conversations
|
||||||
.filter(
|
.filter(
|
||||||
(conversation) =>
|
conversation =>
|
||||||
searchValue === '' ||
|
searchValue === '' ||
|
||||||
conversation.chatName.toLowerCase().includes(searchValue.toLowerCase()),
|
conversation.chatName.toLowerCase().includes(searchValue.toLowerCase())
|
||||||
)
|
)
|
||||||
.map((item) => {
|
.map(item => {
|
||||||
const conversationItemClass = classNames(styles.conversationItem, {
|
const conversationItemClass = classNames(styles.conversationItem, {
|
||||||
[styles.activeConversationItem]: currentConversation?.chatId === item.chatId,
|
[styles.activeConversationItem]: currentConversation?.chatId === item.chatId,
|
||||||
});
|
});
|
||||||
@@ -249,7 +194,7 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
<div className={styles.subTitle}>{item.lastQuestion}</div>
|
<div className={styles.subTitle}>{item.lastQuestion}</div>
|
||||||
<DeleteOutlined
|
<DeleteOutlined
|
||||||
className={styles.deleteIcon}
|
className={styles.deleteIcon}
|
||||||
onClick={(e) => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onDeleteConversation(item.chatId);
|
onDeleteConversation(item.chatId);
|
||||||
}}
|
}}
|
||||||
@@ -277,4 +222,15 @@ const Conversation: ForwardRefRenderFunction<any, Props> = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default forwardRef(Conversation);
|
function areEqual(prevProps: Props, nextProps: Props) {
|
||||||
|
if (
|
||||||
|
prevProps.currentAgent?.id === nextProps.currentAgent?.id &&
|
||||||
|
prevProps.currentConversation?.chatId === nextProps.currentConversation?.chatId &&
|
||||||
|
prevProps.historyVisible === nextProps.historyVisible
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(forwardRef(Conversation), areEqual);
|
||||||
@@ -166,11 +166,6 @@
|
|||||||
width: 400px;
|
width: 400px;
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
border-left: 1px solid #f1f1f1;
|
border-left: 1px solid #f1f1f1;
|
||||||
}
|
z-index: 99;
|
||||||
|
|
||||||
&.copilotMode {
|
|
||||||
&.collapsed {
|
|
||||||
width: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import Text from '../components/Text';
|
import Text from '../components/Text';
|
||||||
import { memo, useCallback, useEffect, useState } from 'react';
|
import { memo, useCallback, useEffect, useState } from 'react';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import { ChatItem } from 'supersonic-chat-sdk';
|
|
||||||
import type { MsgDataType } from 'supersonic-chat-sdk';
|
|
||||||
import { AgentType, MessageItem, MessageTypeEnum } from '../type';
|
import { AgentType, MessageItem, MessageTypeEnum } from '../type';
|
||||||
import { isMobile, updateMessageContainerScroll } from '@/utils/utils';
|
import { isMobile, updateMessageContainerScroll } from '../../utils/utils';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
import AgentTip from '../components/AgentTip';
|
import AgentTip from '../components/AgentTip';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { MsgDataType } from '../../common/type';
|
||||||
|
import ChatItem from '../../components/ChatItem';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -16,13 +16,14 @@ type Props = {
|
|||||||
historyVisible: boolean;
|
historyVisible: boolean;
|
||||||
currentAgent?: AgentType;
|
currentAgent?: AgentType;
|
||||||
chatVisible?: boolean;
|
chatVisible?: boolean;
|
||||||
|
isDeveloper?: boolean;
|
||||||
|
integrateSystem?: string;
|
||||||
onMsgDataLoaded: (
|
onMsgDataLoaded: (
|
||||||
data: MsgDataType,
|
data: MsgDataType,
|
||||||
questionId: string | number,
|
questionId: string | number,
|
||||||
question: string,
|
question: string,
|
||||||
valid: boolean,
|
valid: boolean
|
||||||
) => void;
|
) => void;
|
||||||
onApplyAuth: (model: string) => void;
|
|
||||||
onSendMsg: (value: string) => void;
|
onSendMsg: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
historyVisible,
|
historyVisible,
|
||||||
currentAgent,
|
currentAgent,
|
||||||
chatVisible,
|
chatVisible,
|
||||||
|
isDeveloper,
|
||||||
|
integrateSystem,
|
||||||
onMsgDataLoaded,
|
onMsgDataLoaded,
|
||||||
onSendMsg,
|
onSendMsg,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -56,17 +59,6 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
onResize();
|
onResize();
|
||||||
}, [historyVisible, chatVisible]);
|
}, [historyVisible, chatVisible]);
|
||||||
|
|
||||||
const getFilters = (modelId?: number, entityId?: string) => {
|
|
||||||
if (!modelId || !entityId) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
value: entityId,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const messageContainerClass = classNames(styles.messageContainer, { [styles.mobile]: isMobile });
|
const messageContainerClass = classNames(styles.messageContainer, { [styles.mobile]: isMobile });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -77,15 +69,14 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
id: msgId,
|
id: msgId,
|
||||||
modelId,
|
modelId,
|
||||||
agentId,
|
agentId,
|
||||||
entityId,
|
|
||||||
type,
|
type,
|
||||||
msg,
|
msg,
|
||||||
msgValue,
|
msgValue,
|
||||||
identityMsg,
|
identityMsg,
|
||||||
msgData,
|
msgData,
|
||||||
score,
|
score,
|
||||||
isHistory,
|
|
||||||
parseOptions,
|
parseOptions,
|
||||||
|
filters,
|
||||||
} = msgItem;
|
} = msgItem;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -104,14 +95,16 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
conversationId={chatId}
|
conversationId={chatId}
|
||||||
modelId={modelId}
|
modelId={modelId}
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
filter={getFilters(modelId, entityId)}
|
filter={filters}
|
||||||
isLastMessage={index === messageList.length - 1}
|
isLastMessage={index === messageList.length - 1}
|
||||||
isHistory={isHistory}
|
|
||||||
triggerResize={triggerResize}
|
triggerResize={triggerResize}
|
||||||
|
isDeveloper={isDeveloper}
|
||||||
|
integrateSystem={integrateSystem}
|
||||||
onMsgDataLoaded={(data: MsgDataType, valid: boolean) => {
|
onMsgDataLoaded={(data: MsgDataType, valid: boolean) => {
|
||||||
onMsgDataLoaded(data, msgId, msgValue || msg || '', valid);
|
onMsgDataLoaded(data, msgId, msgValue || msg || '', valid);
|
||||||
}}
|
}}
|
||||||
onUpdateMessageScroll={updateMessageContainerScroll}
|
onUpdateMessageScroll={updateMessageContainerScroll}
|
||||||
|
onSendMsg={onSendMsg}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -121,15 +114,16 @@ const MessageContainer: React.FC<Props> = ({
|
|||||||
conversationId={chatId}
|
conversationId={chatId}
|
||||||
modelId={modelId}
|
modelId={modelId}
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
filter={getFilters(modelId, entityId)}
|
filter={filters}
|
||||||
isLastMessage={index === messageList.length - 1}
|
isLastMessage={index === messageList.length - 1}
|
||||||
isHistory={isHistory}
|
|
||||||
triggerResize={triggerResize}
|
triggerResize={triggerResize}
|
||||||
parseOptions={parseOptions}
|
parseOptions={parseOptions}
|
||||||
|
integrateSystem={integrateSystem}
|
||||||
onMsgDataLoaded={(data: MsgDataType, valid: boolean) => {
|
onMsgDataLoaded={(data: MsgDataType, valid: boolean) => {
|
||||||
onMsgDataLoaded(data, msgId, msgValue || msg || '', valid);
|
onMsgDataLoaded(data, msgId, msgValue || msg || '', valid);
|
||||||
}}
|
}}
|
||||||
onUpdateMessageScroll={updateMessageContainerScroll}
|
onUpdateMessageScroll={updateMessageContainerScroll}
|
||||||
|
onSendMsg={onSendMsg}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import IconFont from '@/components/IconFont';
|
import IconFont from '../../components/IconFont';
|
||||||
import { Drawer } from 'antd';
|
import { Drawer } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { AGENT_ICONS } from '../constants';
|
import { AGENT_ICONS } from '../constants';
|
||||||
import { AgentType } from '../type';
|
import { AgentType } from '../type';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import LeftAvatar from '../CopilotAvatar';
|
import LeftAvatar from '../CopilotAvatar';
|
||||||
import Message from '../Message';
|
import Message from '../Message';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
import { AgentType } from '../../type';
|
import { AgentType } from '../../type';
|
||||||
import { isMobile } from '@/utils/utils';
|
import { isMobile } from '../../../utils/utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentAgent?: AgentType;
|
currentAgent?: AgentType;
|
||||||
@@ -24,7 +24,7 @@ const AgentTip: React.FC<Props> = ({ currentAgent, onSendMsg }) => {
|
|||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div className={styles.examples}>
|
<div className={styles.examples}>
|
||||||
{currentAgent.examples?.length > 0 ? (
|
{currentAgent.examples?.length > 0 ? (
|
||||||
currentAgent.examples.map((example) => (
|
currentAgent.examples.map(example => (
|
||||||
<div
|
<div
|
||||||
key={example}
|
key={example}
|
||||||
className={styles.example}
|
className={styles.example}
|
||||||
@@ -45,7 +45,7 @@ const ConversationModal: React.FC<Props> = ({ visible, editConversation, onClose
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={`修改${CHAT_TITLE}问答名称`}
|
title={`修改${CHAT_TITLE}问答名称`}
|
||||||
visible={visible}
|
open={visible}
|
||||||
onCancel={onClose}
|
onCancel={onClose}
|
||||||
onOk={onConfirm}
|
onOk={onConfirm}
|
||||||
confirmLoading={loading}
|
confirmLoading={loading}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import IconFont from '@/components/IconFont';
|
import IconFont from '../../../components/IconFont';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
|
|
||||||
const CopilotAvatar = () => {
|
const CopilotAvatar = () => {
|
||||||
return <IconFont type="icon-zhinengsuanfa" className={styles.leftAvatar} />;
|
return <IconFont type="icon-zhinengsuanfa" className={styles.leftAvatar} />;
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
position: 'left' | 'right';
|
position: 'left' | 'right';
|
||||||
width?: number | string;
|
width?: number | string;
|
||||||
height?: number | string;
|
height?: number | string;
|
||||||
bubbleClassName?: string;
|
bubbleClassName?: string;
|
||||||
|
children?: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Message: React.FC<Props> = ({ position, width, height, children, bubbleClassName }) => {
|
const Message: React.FC<Props> = ({ position, width, height, children, bubbleClassName }) => {
|
||||||
@@ -21,7 +23,7 @@ const Message: React.FC<Props> = ({ position, width, height, children, bubbleCla
|
|||||||
<div
|
<div
|
||||||
className={`${styles.bubble}${bubbleClassName ? ` ${bubbleClassName}` : ''}`}
|
className={`${styles.bubble}${bubbleClassName ? ` ${bubbleClassName}` : ''}`}
|
||||||
style={{ height }}
|
style={{ height }}
|
||||||
onClick={(e) => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import LeftAvatar from '../CopilotAvatar';
|
import LeftAvatar from '../CopilotAvatar';
|
||||||
import Message from '../Message';
|
import Message from '../Message';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
import { queryRecommendQuestions } from '../../service';
|
import { queryRecommendQuestions } from '../../service';
|
||||||
import Typing from '../Typing';
|
import { isMobile } from '../../../utils/utils';
|
||||||
import { isMobile } from '@/utils/utils';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onSelectQuestion: (value: string) => void;
|
onSelectQuestion: (value: string) => void;
|
||||||
@@ -25,7 +24,7 @@ const RecommendQuestions: React.FC<Props> = ({ onSelectQuestion }) => {
|
|||||||
...item.recommendedQuestions.slice(0, 20).map((item: any) => item.question),
|
...item.recommendedQuestions.slice(0, 20).map((item: any) => item.question),
|
||||||
];
|
];
|
||||||
return result;
|
return result;
|
||||||
}, []) || [],
|
}, []) || []
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ const RecommendQuestions: React.FC<Props> = ({ onSelectQuestion }) => {
|
|||||||
<div className={styles.recommendQuestions}>
|
<div className={styles.recommendQuestions}>
|
||||||
{!isMobile && <LeftAvatar />}
|
{!isMobile && <LeftAvatar />}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Typing />
|
<></>
|
||||||
) : questions.length > 0 ? (
|
) : questions.length > 0 ? (
|
||||||
<Message position="left" bubbleClassName={styles.recommendQuestionsMsg}>
|
<Message position="left" bubbleClassName={styles.recommendQuestionsMsg}>
|
||||||
<div className={styles.title}>推荐问题:</div>
|
<div className={styles.title}>推荐问题:</div>
|
||||||
@@ -5,26 +5,26 @@
|
|||||||
padding: 12px 20px 20px !important;
|
padding: 12px 20px 20px !important;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
column-gap: 16px;
|
column-gap: 16px;
|
||||||
row-gap: 20px;
|
row-gap: 20px;
|
||||||
|
|
||||||
.question {
|
.question {
|
||||||
padding: 0 6px;
|
|
||||||
height: 22px;
|
height: 22px;
|
||||||
line-height: 22px;
|
padding: 0 6px;
|
||||||
font-size: 12px;
|
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
border-radius:11px;
|
font-size: 12px;
|
||||||
|
line-height: 22px;
|
||||||
background-color: #f4f4f4;
|
background-color: #f4f4f4;
|
||||||
|
border-radius: 11px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { isMobile } from '../../utils/utils';
|
||||||
|
import { Avatar } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import LeftAvatar from './CopilotAvatar';
|
import LeftAvatar from './CopilotAvatar';
|
||||||
import Message from './Message';
|
import Message from './Message';
|
||||||
import styles from './style.less';
|
import styles from './style.module.less';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
position: 'left' | 'right';
|
position: 'left' | 'right';
|
||||||
@@ -15,7 +17,7 @@ const Text: React.FC<Props> = ({ position, data, quote }) => {
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<div className={textWrapperClass}>
|
<div className={textWrapperClass}>
|
||||||
{position === 'left' && <LeftAvatar />}
|
{!isMobile && position === 'left' && <LeftAvatar />}
|
||||||
<Message position={position} bubbleClassName={styles.textBubble}>
|
<Message position={position} bubbleClassName={styles.textBubble}>
|
||||||
{position === 'right' && quote && <div className={styles.quote}>{quote}</div>}
|
{position === 'right' && quote && <div className={styles.quote}>{quote}</div>}
|
||||||
<div className={styles.text}>{data}</div>
|
<div className={styles.text}>{data}</div>
|
||||||
@@ -21,7 +21,7 @@ export enum SemanticTypeEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SEMANTIC_TYPE_MAP = {
|
export const SEMANTIC_TYPE_MAP = {
|
||||||
[SemanticTypeEnum.MODEL]: '主题域',
|
[SemanticTypeEnum.MODEL]: '数据来源',
|
||||||
[SemanticTypeEnum.DIMENSION]: '维度',
|
[SemanticTypeEnum.DIMENSION]: '维度',
|
||||||
[SemanticTypeEnum.METRIC]: '指标',
|
[SemanticTypeEnum.METRIC]: '指标',
|
||||||
[SemanticTypeEnum.VALUE]: '维度值',
|
[SemanticTypeEnum.VALUE]: '维度值',
|
||||||
@@ -41,6 +41,8 @@ export const AGENT_ICONS = [
|
|||||||
'icon-mendiankanban',
|
'icon-mendiankanban',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const HOLDER_TAG = '@_supersonic_@';
|
||||||
|
|
||||||
export const CHAT_TITLE = '';
|
export const CHAT_TITLE = '';
|
||||||
|
|
||||||
export const DEFAULT_CONVERSATION_NAME = '新问答对话';
|
export const DEFAULT_CONVERSATION_NAME = '新问答对话';
|
||||||
@@ -49,4 +51,8 @@ export const PAGE_TITLE = '问答对话';
|
|||||||
|
|
||||||
export const WEB_TITLE = '问答对话';
|
export const WEB_TITLE = '问答对话';
|
||||||
|
|
||||||
export const PLACE_HOLDER = '请输入您的问题';
|
export const MOBILE_TITLE = '问答对话';
|
||||||
|
|
||||||
|
export const PLACE_HOLDER = '请输入您的问题,或输入“/”切换助理';
|
||||||
|
|
||||||
|
export const SIMPLE_PLACE_HOLDER = '请输入您的问题';
|
||||||
@@ -1,52 +1,57 @@
|
|||||||
import { updateMessageContainerScroll, isMobile, uuid } from '@/utils/utils';
|
import { updateMessageContainerScroll, isMobile, uuid, setToken } from '../utils/utils';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
|
||||||
import { Helmet, useDispatch } from 'umi';
|
|
||||||
import MessageContainer from './MessageContainer';
|
|
||||||
import styles from './style.less';
|
|
||||||
import {
|
import {
|
||||||
ConversationDetailType,
|
ForwardRefRenderFunction,
|
||||||
DefaultEntityType,
|
forwardRef,
|
||||||
ModelType,
|
useEffect,
|
||||||
MessageItem,
|
useImperativeHandle,
|
||||||
MessageTypeEnum,
|
useRef,
|
||||||
AgentType,
|
useState,
|
||||||
} from './type';
|
} from 'react';
|
||||||
|
import MessageContainer from './MessageContainer';
|
||||||
|
import styles from './style.module.less';
|
||||||
|
import { ConversationDetailType, MessageItem, MessageTypeEnum, AgentType } from './type';
|
||||||
import { queryAgentList } from './service';
|
import { queryAgentList } from './service';
|
||||||
import { useThrottleFn } from 'ahooks';
|
import { useThrottleFn } from 'ahooks';
|
||||||
import Conversation from './Conversation';
|
import Conversation from './Conversation';
|
||||||
import ChatFooter from './ChatFooter';
|
import ChatFooter from './ChatFooter';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { CHAT_TITLE, DEFAULT_CONVERSATION_NAME, WEB_TITLE } from './constants';
|
import { CHAT_TITLE } from './constants';
|
||||||
import { HistoryMsgItemType, MsgDataType, getHistoryMsg } from 'supersonic-chat-sdk';
|
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import 'supersonic-chat-sdk/dist/index.css';
|
|
||||||
import { setToken as setChatSdkToken } from 'supersonic-chat-sdk';
|
|
||||||
import AgentList from './AgentList';
|
import AgentList from './AgentList';
|
||||||
import { AUTH_TOKEN_KEY } from '@/common/constants';
|
|
||||||
import MobileAgents from './MobileAgents';
|
import MobileAgents from './MobileAgents';
|
||||||
|
import { HistoryMsgItemType, MsgDataType, SendMsgParamsType } from '../common/type';
|
||||||
|
import { getHistoryMsg } from '../service';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isCopilotMode?: boolean;
|
token?: string;
|
||||||
defaultModelName?: string;
|
agentIds?: number[];
|
||||||
defaultEntityFilter?: DefaultEntityType;
|
initialAgentId?: number;
|
||||||
copilotSendMsg?: string;
|
|
||||||
triggerNewConversation?: boolean;
|
|
||||||
chatVisible?: boolean;
|
chatVisible?: boolean;
|
||||||
onNewConversationTriggered?: () => void;
|
noInput?: boolean;
|
||||||
onCurrentModelChange?: (model?: ModelType) => void;
|
isDeveloper?: boolean;
|
||||||
|
integrateSystem?: string;
|
||||||
|
isCopilot?: boolean;
|
||||||
|
apiUrl?: string;
|
||||||
|
onCurrentAgentChange?: (agent?: AgentType) => void;
|
||||||
|
onReportMsgEvent?: (msg: string, valid: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Chat: React.FC<Props> = ({
|
const Chat: ForwardRefRenderFunction<any, Props> = (
|
||||||
isCopilotMode,
|
{
|
||||||
defaultModelName,
|
token,
|
||||||
defaultEntityFilter,
|
agentIds,
|
||||||
copilotSendMsg,
|
initialAgentId,
|
||||||
triggerNewConversation,
|
chatVisible,
|
||||||
chatVisible,
|
noInput,
|
||||||
onNewConversationTriggered,
|
isDeveloper,
|
||||||
}) => {
|
integrateSystem,
|
||||||
const isMobileMode = isMobile || isCopilotMode;
|
isCopilot,
|
||||||
|
apiUrl,
|
||||||
|
onCurrentAgentChange,
|
||||||
|
onReportMsgEvent,
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
const [messageList, setMessageList] = useState<MessageItem[]>([]);
|
const [messageList, setMessageList] = useState<MessageItem[]>([]);
|
||||||
const [inputMsg, setInputMsg] = useState('');
|
const [inputMsg, setInputMsg] = useState('');
|
||||||
const [pageNo, setPageNo] = useState(1);
|
const [pageNo, setPageNo] = useState(1);
|
||||||
@@ -56,95 +61,97 @@ const Chat: React.FC<Props> = ({
|
|||||||
ConversationDetailType | undefined
|
ConversationDetailType | undefined
|
||||||
>(isMobile ? { chatId: 0, chatName: `${CHAT_TITLE}问答` } : undefined);
|
>(isMobile ? { chatId: 0, chatName: `${CHAT_TITLE}问答` } : undefined);
|
||||||
const [historyVisible, setHistoryVisible] = useState(false);
|
const [historyVisible, setHistoryVisible] = useState(false);
|
||||||
const [defaultEntity, setDefaultEntity] = useState<DefaultEntityType>();
|
|
||||||
const [agentList, setAgentList] = useState<AgentType[]>([]);
|
const [agentList, setAgentList] = useState<AgentType[]>([]);
|
||||||
const [currentAgent, setCurrentAgent] = useState<AgentType>();
|
const [currentAgent, setCurrentAgent] = useState<AgentType>();
|
||||||
const [mobileAgentsVisible, setMobileAgentsVisible] = useState(false);
|
const [mobileAgentsVisible, setMobileAgentsVisible] = useState(false);
|
||||||
const dispatch = useDispatch();
|
const [agentListVisible, setAgentListVisible] = useState(true);
|
||||||
|
|
||||||
const conversationRef = useRef<any>();
|
const conversationRef = useRef<any>();
|
||||||
const chatFooterRef = useRef<any>();
|
const chatFooterRef = useRef<any>();
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
sendCopilotMsg,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sendCopilotMsg = (params: SendMsgParamsType) => {
|
||||||
|
setAgentListVisible(false);
|
||||||
|
const { agentId, msg, modelId } = params;
|
||||||
|
if (currentAgent?.id !== agentId) {
|
||||||
|
setMessageList([]);
|
||||||
|
const agent = agentList.find(item => item.id === agentId) || ({} as AgentType);
|
||||||
|
updateCurrentAgent({ ...agent, initialSendMsgParams: params });
|
||||||
|
} else {
|
||||||
|
onSendMsg(msg, messageList, modelId, params);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateCurrentAgent = (agent?: AgentType) => {
|
||||||
|
setCurrentAgent(agent);
|
||||||
|
onCurrentAgentChange?.(agent);
|
||||||
|
localStorage.setItem('AGENT_ID', `${agent?.id}`);
|
||||||
|
if (!isCopilot) {
|
||||||
|
window.history.replaceState({}, '', `${window.location.pathname}?agentId=${agent?.id}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const initAgentList = async () => {
|
const initAgentList = async () => {
|
||||||
const res = await queryAgentList();
|
const res = await queryAgentList();
|
||||||
const agentListValue = (res.data || []).filter((item) => item.status === 1);
|
const agentListValue = (res.data || []).filter(
|
||||||
|
item => item.status === 1 && (agentIds === undefined || agentIds.includes(item.id))
|
||||||
|
);
|
||||||
setAgentList(agentListValue);
|
setAgentList(agentListValue);
|
||||||
if (agentListValue.length > 0) {
|
if (agentListValue.length > 0) {
|
||||||
setCurrentAgent(agentListValue[0]);
|
const agentId = initialAgentId || localStorage.getItem('AGENT_ID');
|
||||||
|
if (agentId) {
|
||||||
|
const agent = agentListValue.find(item => item.id === +agentId);
|
||||||
|
updateCurrentAgent(agent || agentListValue[0]);
|
||||||
|
} else {
|
||||||
|
updateCurrentAgent(agentListValue[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setChatSdkToken(localStorage.getItem(AUTH_TOKEN_KEY) || '');
|
|
||||||
initAgentList();
|
initAgentList();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (token) {
|
||||||
|
setToken(token);
|
||||||
|
}
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (apiUrl) {
|
||||||
|
localStorage.setItem('SUPERSONIC_CHAT_API_URL', apiUrl);
|
||||||
|
}
|
||||||
|
}, [apiUrl]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (chatVisible) {
|
if (chatVisible) {
|
||||||
|
inputFocus();
|
||||||
updateMessageContainerScroll();
|
updateMessageContainerScroll();
|
||||||
}
|
}
|
||||||
}, [chatVisible]);
|
}, [chatVisible]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (triggerNewConversation) {
|
|
||||||
setCurrentAgent(agentList?.find((item) => item.name === '做分析'));
|
|
||||||
conversationRef.current?.onAddConversation({
|
|
||||||
type: 'CUSTOMIZE',
|
|
||||||
modelId: defaultEntityFilter?.modelId,
|
|
||||||
entityId: defaultEntityFilter?.entityId,
|
|
||||||
agent: agentList?.find((item) => item.name === '做分析'),
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
onNewConversationTriggered?.();
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
}, [triggerNewConversation]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentConversation) {
|
if (!currentConversation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { initMsg, modelId, entityId, agent } = currentConversation;
|
const { initialMsgParams, isAdd } = currentConversation;
|
||||||
if (initMsg) {
|
if (isAdd) {
|
||||||
inputFocus();
|
inputFocus();
|
||||||
if (initMsg === 'CUSTOMIZE' && copilotSendMsg) {
|
if (initialMsgParams) {
|
||||||
onSendMsg(
|
onSendMsg(initialMsgParams.msg, [], initialMsgParams.modelId, initialMsgParams);
|
||||||
copilotSendMsg,
|
|
||||||
[],
|
|
||||||
modelId,
|
|
||||||
entityId,
|
|
||||||
agentList.find((item) => item.name === '做分析'),
|
|
||||||
);
|
|
||||||
dispatch({
|
|
||||||
type: 'globalState/setCopilotSendMsg',
|
|
||||||
payload: '',
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (initMsg === DEFAULT_CONVERSATION_NAME || initMsg.includes('CUSTOMIZE')) {
|
sendHelloRsp();
|
||||||
if (agent) {
|
|
||||||
setCurrentAgent(agent);
|
|
||||||
}
|
|
||||||
sendHelloRsp(agent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onSendMsg(
|
|
||||||
initMsg,
|
|
||||||
[],
|
|
||||||
modelId,
|
|
||||||
entityId,
|
|
||||||
initMsg.includes('商业线索') ? agentList.find((item) => item.name === '做分析') : undefined,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateHistoryMsg(1);
|
updateHistoryMsg(1);
|
||||||
setPageNo(1);
|
setPageNo(1);
|
||||||
}, [currentConversation]);
|
}, [currentConversation]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setDefaultEntity(defaultEntityFilter);
|
|
||||||
}, [defaultEntityFilter]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (historyInited) {
|
if (historyInited) {
|
||||||
const messageContainerEle = document.getElementById('messageContainer');
|
const messageContainerEle = document.getElementById('messageContainer');
|
||||||
@@ -157,11 +164,14 @@ const Chat: React.FC<Props> = ({
|
|||||||
}, [historyInited]);
|
}, [historyInited]);
|
||||||
|
|
||||||
const sendHelloRsp = (agent?: AgentType) => {
|
const sendHelloRsp = (agent?: AgentType) => {
|
||||||
|
if (noInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setMessageList([
|
setMessageList([
|
||||||
{
|
{
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: MessageTypeEnum.AGENT_LIST,
|
type: MessageTypeEnum.AGENT_LIST,
|
||||||
msg: agent?.name || currentAgent?.name || '查信息',
|
msg: agent?.name || currentAgent?.name || agentList?.[0].name,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
@@ -173,13 +183,12 @@ const Chat: React.FC<Props> = ({
|
|||||||
msg: item.queryText,
|
msg: item.queryText,
|
||||||
msgData: item.queryResult,
|
msgData: item.queryResult,
|
||||||
score: item.score,
|
score: item.score,
|
||||||
isHistory: true,
|
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateHistoryMsg = async (page: number) => {
|
const updateHistoryMsg = async (page: number) => {
|
||||||
const res = await getHistoryMsg(page, currentConversation!.chatId, 3);
|
const res = await getHistoryMsg(page, currentConversation!.chatId, 3);
|
||||||
const { hasNextPage, list } = res.data?.data || { hasNextPage: false, list: [] };
|
const { hasNextPage, list } = res?.data || { hasNextPage: false, list: [] };
|
||||||
const msgList = [...convertHistoryMsg(list), ...(page === 1 ? [] : messageList)];
|
const msgList = [...convertHistoryMsg(list), ...(page === 1 ? [] : messageList)];
|
||||||
setMessageList(msgList);
|
setMessageList(msgList);
|
||||||
setHasNextPage(hasNextPage);
|
setHasNextPage(hasNextPage);
|
||||||
@@ -197,7 +206,7 @@ const Chat: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { run: handleScroll } = useThrottleFn(
|
const { run: handleScroll } = useThrottleFn(
|
||||||
(e) => {
|
e => {
|
||||||
if (e.target.scrollTop === 0 && hasNextPage) {
|
if (e.target.scrollTop === 0 && hasNextPage) {
|
||||||
updateHistoryMsg(pageNo + 1);
|
updateHistoryMsg(pageNo + 1);
|
||||||
setPageNo(pageNo + 1);
|
setPageNo(pageNo + 1);
|
||||||
@@ -207,7 +216,7 @@ const Chat: React.FC<Props> = ({
|
|||||||
leading: true,
|
leading: true,
|
||||||
trailing: true,
|
trailing: true,
|
||||||
wait: 200,
|
wait: 200,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const inputFocus = () => {
|
const inputFocus = () => {
|
||||||
@@ -224,8 +233,7 @@ const Chat: React.FC<Props> = ({
|
|||||||
msg?: string,
|
msg?: string,
|
||||||
list?: MessageItem[],
|
list?: MessageItem[],
|
||||||
modelId?: number,
|
modelId?: number,
|
||||||
entityId?: string,
|
sendMsgParams?: SendMsgParamsType
|
||||||
agent?: AgentType,
|
|
||||||
) => {
|
) => {
|
||||||
const currentMsg = msg || inputMsg;
|
const currentMsg = msg || inputMsg;
|
||||||
if (currentMsg.trim() === '') {
|
if (currentMsg.trim() === '') {
|
||||||
@@ -233,13 +241,14 @@ const Chat: React.FC<Props> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const msgAgent = agentList.find((item) => currentMsg.indexOf(item.name) === 1);
|
const msgAgent = agentList.find(item => currentMsg.indexOf(item.name) === 1);
|
||||||
const certainAgent = currentMsg[0] === '/' && msgAgent;
|
const certainAgent = currentMsg[0] === '/' && msgAgent;
|
||||||
const agentIdValue = certainAgent ? msgAgent.id : undefined;
|
const agentIdValue = certainAgent ? msgAgent.id : undefined;
|
||||||
if (agent || certainAgent) {
|
const agent = agentList.find(item => item.id === sendMsgParams?.agentId);
|
||||||
setCurrentAgent(agent || msgAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (agent || certainAgent) {
|
||||||
|
updateCurrentAgent(agent || msgAgent);
|
||||||
|
}
|
||||||
const msgs = [
|
const msgs = [
|
||||||
...(list || messageList),
|
...(list || messageList),
|
||||||
{
|
{
|
||||||
@@ -250,8 +259,8 @@ const Chat: React.FC<Props> = ({
|
|||||||
: currentMsg,
|
: currentMsg,
|
||||||
modelId: modelId === -1 ? undefined : modelId,
|
modelId: modelId === -1 ? undefined : modelId,
|
||||||
agentId: agent?.id || agentIdValue || currentAgent?.id,
|
agentId: agent?.id || agentIdValue || currentAgent?.id,
|
||||||
entityId: entityId || defaultEntity?.entityId,
|
|
||||||
type: MessageTypeEnum.QUESTION,
|
type: MessageTypeEnum.QUESTION,
|
||||||
|
filters: sendMsgParams?.filters,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
setMessageList(msgs);
|
setMessageList(msgs);
|
||||||
@@ -276,35 +285,26 @@ const Chat: React.FC<Props> = ({
|
|||||||
|
|
||||||
const onSelectConversation = (
|
const onSelectConversation = (
|
||||||
conversation: ConversationDetailType,
|
conversation: ConversationDetailType,
|
||||||
name?: string,
|
sendMsgParams?: SendMsgParamsType,
|
||||||
modelId?: number,
|
isAdd?: boolean
|
||||||
entityId?: string,
|
|
||||||
agent?: AgentType,
|
|
||||||
) => {
|
) => {
|
||||||
if (!isMobileMode) {
|
|
||||||
window.history.replaceState('', '', `?q=${conversation.chatName}&cid=${conversation.chatId}`);
|
|
||||||
}
|
|
||||||
setCurrentConversation({
|
setCurrentConversation({
|
||||||
...conversation,
|
...conversation,
|
||||||
initMsg: name,
|
initialMsgParams: sendMsgParams,
|
||||||
modelId,
|
isAdd,
|
||||||
entityId,
|
|
||||||
agent,
|
|
||||||
});
|
});
|
||||||
saveConversationToLocal(conversation);
|
saveConversationToLocal(conversation);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reportMsgEvent = (msg: string, valid: boolean) => {};
|
|
||||||
|
|
||||||
const onMsgDataLoaded = (
|
const onMsgDataLoaded = (
|
||||||
data: MsgDataType,
|
data: MsgDataType,
|
||||||
questionId: string | number,
|
questionId: string | number,
|
||||||
question: string,
|
question: string,
|
||||||
valid: boolean,
|
valid: boolean
|
||||||
) => {
|
) => {
|
||||||
reportMsgEvent(question, valid);
|
onReportMsgEvent?.(question, valid);
|
||||||
if (!isMobile) {
|
if (!isMobile) {
|
||||||
conversationRef?.current?.updateData();
|
conversationRef?.current?.updateData(currentAgent?.id);
|
||||||
}
|
}
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
@@ -319,7 +319,7 @@ const Chat: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const msgs = cloneDeep(messageList);
|
const msgs = cloneDeep(messageList);
|
||||||
const msg = msgs.find((item) => item.id === questionId);
|
const msg = msgs.find(item => item.id === questionId);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.msgData = data;
|
msg.msgData = data;
|
||||||
const msgList = [...msgs, ...(parseOptionsItem ? [parseOptionsItem] : [])];
|
const msgList = [...msgs, ...(parseOptionsItem ? [parseOptionsItem] : [])];
|
||||||
@@ -332,10 +332,8 @@ const Chat: React.FC<Props> = ({
|
|||||||
setHistoryVisible(!historyVisible);
|
setHistoryVisible(!historyVisible);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onApplyAuth = (model: string) => {};
|
const onAddConversation = () => {
|
||||||
|
conversationRef.current?.onAddConversation();
|
||||||
const onAddConversation = (agent?: AgentType) => {
|
|
||||||
conversationRef.current?.onAddConversation({ agent });
|
|
||||||
inputFocus();
|
inputFocus();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -343,7 +341,10 @@ const Chat: React.FC<Props> = ({
|
|||||||
if (agent.id === currentAgent?.id) {
|
if (agent.id === currentAgent?.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setCurrentAgent(agent);
|
if (messageList.length === 1 && messageList[0].type === MessageTypeEnum.AGENT_LIST) {
|
||||||
|
setMessageList([]);
|
||||||
|
}
|
||||||
|
updateCurrentAgent(agent);
|
||||||
updateMessageContainerScroll();
|
updateMessageContainerScroll();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -365,9 +366,8 @@ const Chat: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={chatClass}>
|
<div className={chatClass}>
|
||||||
{!isMobileMode && <Helmet title={WEB_TITLE} />}
|
|
||||||
<div className={styles.chatSection}>
|
<div className={styles.chatSection}>
|
||||||
{!isMobile && (
|
{!isMobile && agentList.length > 1 && agentListVisible && (
|
||||||
<AgentList
|
<AgentList
|
||||||
agentList={agentList}
|
agentList={agentList}
|
||||||
currentAgent={currentAgent}
|
currentAgent={currentAgent}
|
||||||
@@ -378,7 +378,7 @@ const Chat: React.FC<Props> = ({
|
|||||||
{currentConversation && (
|
{currentConversation && (
|
||||||
<div className={styles.chatBody}>
|
<div className={styles.chatBody}>
|
||||||
<div className={styles.chatContent}>
|
<div className={styles.chatContent}>
|
||||||
{currentAgent && !isMobile && (
|
{currentAgent && !isMobile && !noInput && (
|
||||||
<div className={styles.chatHeader}>
|
<div className={styles.chatHeader}>
|
||||||
<div className={styles.chatHeaderTitle}>{currentAgent.name}</div>
|
<div className={styles.chatHeaderTitle}>{currentAgent.name}</div>
|
||||||
<div className={styles.chatHeaderTip}>{currentAgent.description}</div>
|
<div className={styles.chatHeaderTip}>{currentAgent.description}</div>
|
||||||
@@ -391,38 +391,40 @@ const Chat: React.FC<Props> = ({
|
|||||||
historyVisible={historyVisible}
|
historyVisible={historyVisible}
|
||||||
currentAgent={currentAgent}
|
currentAgent={currentAgent}
|
||||||
chatVisible={chatVisible}
|
chatVisible={chatVisible}
|
||||||
|
isDeveloper={isDeveloper}
|
||||||
|
integrateSystem={integrateSystem}
|
||||||
onMsgDataLoaded={onMsgDataLoaded}
|
onMsgDataLoaded={onMsgDataLoaded}
|
||||||
onApplyAuth={onApplyAuth}
|
|
||||||
onSendMsg={onSendMsg}
|
onSendMsg={onSendMsg}
|
||||||
/>
|
/>
|
||||||
<ChatFooter
|
{!noInput && (
|
||||||
inputMsg={inputMsg}
|
<ChatFooter
|
||||||
chatId={currentConversation?.chatId}
|
inputMsg={inputMsg}
|
||||||
agentList={agentList}
|
chatId={currentConversation?.chatId}
|
||||||
currentAgent={currentAgent}
|
agentList={agentList}
|
||||||
onToggleHistoryVisible={onToggleHistoryVisible}
|
currentAgent={currentAgent}
|
||||||
onInputMsgChange={onInputMsgChange}
|
onToggleHistoryVisible={onToggleHistoryVisible}
|
||||||
onSendMsg={sendMsg}
|
onInputMsgChange={onInputMsgChange}
|
||||||
onAddConversation={onAddConversation}
|
onSendMsg={sendMsg}
|
||||||
onSelectAgent={onSelectAgent}
|
onAddConversation={onAddConversation}
|
||||||
onOpenMobileAgents={() => {
|
onSelectAgent={onSelectAgent}
|
||||||
setMobileAgentsVisible(true);
|
onOpenAgents={() => {
|
||||||
}}
|
if (isMobile) {
|
||||||
ref={chatFooterRef}
|
setMobileAgentsVisible(true);
|
||||||
/>
|
} else {
|
||||||
|
setAgentListVisible(!agentListVisible);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
ref={chatFooterRef}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Conversation
|
<Conversation
|
||||||
agentList={agentList}
|
|
||||||
currentAgent={currentAgent}
|
currentAgent={currentAgent}
|
||||||
currentConversation={currentConversation}
|
currentConversation={currentConversation}
|
||||||
historyVisible={historyVisible}
|
historyVisible={historyVisible}
|
||||||
isCopilotMode={isCopilotMode}
|
|
||||||
defaultEntityFilter={defaultEntityFilter}
|
|
||||||
triggerNewConversation={triggerNewConversation}
|
|
||||||
onNewConversationTriggered={onNewConversationTriggered}
|
|
||||||
onSelectConversation={onSelectConversation}
|
onSelectConversation={onSelectConversation}
|
||||||
onCloseConversation={onCloseConversation}
|
onCloseConversation={onCloseConversation}
|
||||||
ref={conversationRef}
|
ref={conversationRef}
|
||||||
@@ -441,4 +443,4 @@ const Chat: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Chat;
|
export default forwardRef(Chat);
|
||||||
51
webapp/packages/chat-sdk/src/Chat/service.ts
Normal file
51
webapp/packages/chat-sdk/src/Chat/service.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import axios from '../service/axiosInstance';
|
||||||
|
import { isMobile } from '../utils/utils';
|
||||||
|
import { AgentType, ModelType } from './type';
|
||||||
|
|
||||||
|
const prefix = isMobile ? '/openapi' : '/api';
|
||||||
|
|
||||||
|
export function saveConversation(chatName: string, agentId: number) {
|
||||||
|
return axios.post<any>(
|
||||||
|
`${prefix}/chat/manage/save?chatName=${chatName}&agentId=${agentId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateConversationName(chatName: string, chatId: number = 0) {
|
||||||
|
return axios.post<any>(
|
||||||
|
`${prefix}/chat/manage/updateChatName?chatName=${chatName}&chatId=${chatId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteConversation(chatId: number) {
|
||||||
|
return axios.post<any>(`${prefix}/chat/manage/delete?chatId=${chatId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllConversations(agentId?: number) {
|
||||||
|
return axios.get<any>(`${prefix}/chat/manage/getAll`, { params: { agentId } });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getModelList() {
|
||||||
|
return axios.get<ModelType[]>(`${prefix}/chat/conf/modelList/view`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateQAFeedback(questionId: number, score: number) {
|
||||||
|
return axios.post<any>(
|
||||||
|
`${prefix}/chat/manage/updateQAFeedback?id=${questionId}&score=${score}&feedback=`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryMetricSuggestion(modelId: number) {
|
||||||
|
return axios.get<any>(`${prefix}/chat/recommend/metric/${modelId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function querySuggestion(modelId: number) {
|
||||||
|
return axios.get<any>(`${prefix}/chat/recommend/${modelId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryRecommendQuestions() {
|
||||||
|
return axios.get<any>(`${prefix}/chat/recommend/question`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryAgentList() {
|
||||||
|
return axios.get<AgentType[]>(`${prefix}/chat/agent/getAgentList`);
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
@import '~antd/es/style/themes/default.less';
|
|
||||||
|
|
||||||
.chat {
|
.chat {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -33,7 +31,7 @@
|
|||||||
.chatHeader {
|
.chatHeader {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 999;
|
z-index: 9;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ChatContextType, MsgDataType } from 'supersonic-chat-sdk';
|
import { ChatContextType, MsgDataType, SendMsgParamsType } from "../common/type";
|
||||||
|
|
||||||
export enum MessageTypeEnum {
|
export enum MessageTypeEnum {
|
||||||
TEXT = 'text', // 指标文本
|
TEXT = 'text', // 指标文本
|
||||||
@@ -27,8 +27,8 @@ export type MessageItem = {
|
|||||||
quote?: string;
|
quote?: string;
|
||||||
score?: number;
|
score?: number;
|
||||||
feedback?: string;
|
feedback?: string;
|
||||||
isHistory?: boolean;
|
|
||||||
parseOptions?: ChatContextType[];
|
parseOptions?: ChatContextType[];
|
||||||
|
filters?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ConversationDetailType = {
|
export type ConversationDetailType = {
|
||||||
@@ -38,10 +38,8 @@ export type ConversationDetailType = {
|
|||||||
creator?: string;
|
creator?: string;
|
||||||
lastQuestion?: string;
|
lastQuestion?: string;
|
||||||
lastTime?: string;
|
lastTime?: string;
|
||||||
initMsg?: string;
|
initialMsgParams?: SendMsgParamsType;
|
||||||
modelId?: number;
|
isAdd?: boolean;
|
||||||
entityId?: string;
|
|
||||||
agent?: AgentType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum MessageModeEnum {
|
export enum MessageModeEnum {
|
||||||
@@ -67,13 +65,6 @@ export type PluginType = {
|
|||||||
comment: string;
|
comment: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DefaultEntityType = {
|
|
||||||
entityId: string;
|
|
||||||
entityName: string;
|
|
||||||
modelName?: string;
|
|
||||||
modelId?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SuggestionItemType = {
|
export type SuggestionItemType = {
|
||||||
id: number;
|
id: number;
|
||||||
model: number;
|
model: number;
|
||||||
@@ -92,4 +83,5 @@ export type AgentType = {
|
|||||||
description: string;
|
description: string;
|
||||||
examples: string[];
|
examples: string[];
|
||||||
status: 0 | 1;
|
status: 0 | 1;
|
||||||
|
initialSendMsgParams?: SendMsgParamsType;
|
||||||
};
|
};
|
||||||
148
webapp/packages/chat-sdk/src/Copilot/index.tsx
Normal file
148
webapp/packages/chat-sdk/src/Copilot/index.tsx
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
import IconFont from '../components/IconFont';
|
||||||
|
import { CaretRightOutlined, CloseOutlined } from '@ant-design/icons';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
ForwardRefRenderFunction,
|
||||||
|
forwardRef,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import Chat from '../Chat';
|
||||||
|
import { AgentType } from '../Chat/type';
|
||||||
|
import { setToken } from '../utils/utils';
|
||||||
|
import { SendMsgParamsType } from '../common/type';
|
||||||
|
import styles from './style.module.less';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
token?: string;
|
||||||
|
agentIds?: number[];
|
||||||
|
noInput?: boolean;
|
||||||
|
isDeveloper?: boolean;
|
||||||
|
integrateSystem?: string;
|
||||||
|
apiUrl?: string;
|
||||||
|
onReportMsgEvent?: (msg: string, valid: boolean) => void;
|
||||||
|
onOpenChatPage?: (agentId?: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Copilot: ForwardRefRenderFunction<any, Props> = (
|
||||||
|
{
|
||||||
|
token,
|
||||||
|
agentIds,
|
||||||
|
noInput,
|
||||||
|
isDeveloper,
|
||||||
|
integrateSystem,
|
||||||
|
apiUrl,
|
||||||
|
onReportMsgEvent,
|
||||||
|
onOpenChatPage,
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const [chatVisible, setChatVisible] = useState(false);
|
||||||
|
const [copilotMinimized, setCopilotMinimized] = useState(false);
|
||||||
|
const [currentAgent, setCurrentAgent] = useState<AgentType>();
|
||||||
|
|
||||||
|
const chatRef = useRef<any>();
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
sendCopilotMsg,
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (token) {
|
||||||
|
setToken(token);
|
||||||
|
}
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (apiUrl) {
|
||||||
|
localStorage.setItem('SUPERSONIC_CHAT_API_URL', apiUrl);
|
||||||
|
}
|
||||||
|
}, [apiUrl]);
|
||||||
|
|
||||||
|
const sendCopilotMsg = (params: SendMsgParamsType) => {
|
||||||
|
chatRef?.current?.sendCopilotMsg(params);
|
||||||
|
updateChatVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateChatVisible = (visible: boolean) => {
|
||||||
|
setChatVisible(visible);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onToggleChatVisible = () => {
|
||||||
|
updateChatVisible(!chatVisible);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCloseChat = () => {
|
||||||
|
updateChatVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTransferChat = () => {
|
||||||
|
onOpenChatPage?.(currentAgent?.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMinimizeCopilot = (e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
updateChatVisible(false);
|
||||||
|
setCopilotMinimized(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const copilotClass = classNames(styles.copilot, {
|
||||||
|
[styles.copilotMinimized]: copilotMinimized,
|
||||||
|
});
|
||||||
|
|
||||||
|
const chatPopoverClass = classNames(styles.chatPopover, {
|
||||||
|
[styles.c2System]: integrateSystem === 'c2',
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={copilotClass}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setCopilotMinimized(false);
|
||||||
|
}}
|
||||||
|
onClick={onToggleChatVisible}
|
||||||
|
>
|
||||||
|
<IconFont type="icon-copilot-fill" />
|
||||||
|
<div className={styles.minimizeWrapper} onClick={onMinimizeCopilot}>
|
||||||
|
<div className={styles.minimize}>-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.copilotContent} style={{ display: chatVisible ? 'block' : 'none' }}>
|
||||||
|
<div className={chatPopoverClass}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
<div className={styles.leftSection}>
|
||||||
|
<CloseOutlined className={styles.close} onClick={onCloseChat} />
|
||||||
|
{onOpenChatPage && (
|
||||||
|
<IconFont
|
||||||
|
type="icon-weibiaoti-"
|
||||||
|
className={styles.transfer}
|
||||||
|
onClick={onTransferChat}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.title}>内容库问答</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.chat}>
|
||||||
|
<Chat
|
||||||
|
chatVisible={chatVisible}
|
||||||
|
agentIds={agentIds}
|
||||||
|
noInput={noInput}
|
||||||
|
isDeveloper={isDeveloper}
|
||||||
|
integrateSystem={integrateSystem}
|
||||||
|
isCopilot
|
||||||
|
onCurrentAgentChange={setCurrentAgent}
|
||||||
|
onReportMsgEvent={onReportMsgEvent}
|
||||||
|
ref={chatRef}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CaretRightOutlined className={styles.rightArrow} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default forwardRef(Copilot);
|
||||||
@@ -25,24 +25,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.minimizeWrapper {
|
.minimizeWrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: -18px;
|
||||||
|
right: -6px;
|
||||||
display: none;
|
display: none;
|
||||||
cursor: pointer;
|
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
position: absolute;
|
|
||||||
right: -6px;
|
|
||||||
top: -18px;
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.minimize {
|
.minimize {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 50%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding-bottom: 5px;
|
||||||
background-color: var(--text-color-fifth-4);
|
background-color: var(--text-color-fifth-4);
|
||||||
|
border-radius: 50%;
|
||||||
transition: all 0.1s ease-in-out;
|
transition: all 0.1s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +78,10 @@
|
|||||||
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out,
|
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out,
|
||||||
-webkit-transform 0.3s ease-in-out;
|
-webkit-transform 0.3s ease-in-out;
|
||||||
|
|
||||||
|
&.c2System {
|
||||||
|
width: calc(100vw - 180px);
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
@@ -47,8 +47,8 @@ export type FilterItemType = {
|
|||||||
elementID: number;
|
elementID: number;
|
||||||
name: string;
|
name: string;
|
||||||
bizName: string;
|
bizName: string;
|
||||||
operator: string;
|
operator?: string;
|
||||||
type: string;
|
type?: string;
|
||||||
value: any;
|
value: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,6 +69,12 @@ export type EntityDimensionType = {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SqlInfoType = {
|
||||||
|
llmParseSql: string;
|
||||||
|
logicSql: string;
|
||||||
|
querySql: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type ChatContextType = {
|
export type ChatContextType = {
|
||||||
id: number;
|
id: number;
|
||||||
queryId: number;
|
queryId: number;
|
||||||
@@ -86,6 +92,7 @@ export type ChatContextType = {
|
|||||||
queryMode: string;
|
queryMode: string;
|
||||||
dimensionFilters: FilterItemType[];
|
dimensionFilters: FilterItemType[];
|
||||||
properties: any;
|
properties: any;
|
||||||
|
sqlInfo: SqlInfoType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum MsgValidTypeEnum {
|
export enum MsgValidTypeEnum {
|
||||||
@@ -143,6 +150,7 @@ export type ParseDataType = {
|
|||||||
state: ParseStateEnum;
|
state: ParseStateEnum;
|
||||||
selectedParses: ChatContextType[];
|
selectedParses: ChatContextType[];
|
||||||
candidateParses: ChatContextType[];
|
candidateParses: ChatContextType[];
|
||||||
|
similarSolvedQuery: SimilarQuestionType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryDataType = {
|
export type QueryDataType = {
|
||||||
@@ -173,7 +181,7 @@ export enum SemanticTypeEnum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SEMANTIC_TYPE_MAP = {
|
export const SEMANTIC_TYPE_MAP = {
|
||||||
[SemanticTypeEnum.DOMAIN]: '数据模型',
|
[SemanticTypeEnum.DOMAIN]: '数据来源',
|
||||||
[SemanticTypeEnum.DIMENSION]: '维度',
|
[SemanticTypeEnum.DIMENSION]: '维度',
|
||||||
[SemanticTypeEnum.METRIC]: '指标',
|
[SemanticTypeEnum.METRIC]: '指标',
|
||||||
[SemanticTypeEnum.VALUE]: '维度值',
|
[SemanticTypeEnum.VALUE]: '维度值',
|
||||||
@@ -217,4 +225,17 @@ export type DrillDownDimensionType = {
|
|||||||
model: number;
|
model: number;
|
||||||
name: string;
|
name: string;
|
||||||
bizName: string;
|
bizName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SendMsgParamsType = {
|
||||||
|
msg: string;
|
||||||
|
agentId: number;
|
||||||
|
modelId: number;
|
||||||
|
filters?: FilterItemType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SimilarQuestionType = {
|
||||||
|
// queryId: number;
|
||||||
|
// parseId: number;
|
||||||
|
queryText: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const ExecuteItem: React.FC<Props> = ({
|
|||||||
<>
|
<>
|
||||||
<div className={`${prefixCls}-title-bar`}>
|
<div className={`${prefixCls}-title-bar`}>
|
||||||
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
||||||
<div className={`${prefixCls}-step-title`}>数据查询结果</div>
|
<div className={`${prefixCls}-step-title`}>数据查询</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${prefixCls}-content-container ${prefixCls}-last-node`}>
|
<div className={`${prefixCls}-content-container ${prefixCls}-last-node`}>
|
||||||
<Spin spinning={entitySwitchLoading}>
|
<Spin spinning={entitySwitchLoading}>
|
||||||
@@ -68,7 +68,12 @@ const ExecuteItem: React.FC<Props> = ({
|
|||||||
{data?.queryMode === 'WEB_PAGE' ? (
|
{data?.queryMode === 'WEB_PAGE' ? (
|
||||||
<WebPage id={queryId!} data={data} />
|
<WebPage id={queryId!} data={data} />
|
||||||
) : (
|
) : (
|
||||||
<ChatMsg data={data} chartIndex={chartIndex} triggerResize={triggerResize} />
|
<ChatMsg
|
||||||
|
queryId={queryId}
|
||||||
|
data={data}
|
||||||
|
chartIndex={chartIndex}
|
||||||
|
triggerResize={triggerResize}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const FilterItem: React.FC<Props> = ({ modelId, filters, filter, onFiltersChange
|
|||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
const { data } = await queryDimensionValues(modelId, filter.bizName, '');
|
const { data } = await queryDimensionValues(modelId, filter.bizName, '');
|
||||||
setOptions(
|
setOptions(
|
||||||
data?.data?.resultList.map((item: any) => ({
|
data?.resultList.map((item: any) => ({
|
||||||
label: item[filter.bizName],
|
label: item[filter.bizName],
|
||||||
value: item[filter.bizName],
|
value: item[filter.bizName],
|
||||||
})) || []
|
})) || []
|
||||||
@@ -47,9 +47,8 @@ const FilterItem: React.FC<Props> = ({ modelId, filters, filter, onFiltersChange
|
|||||||
if (fetchId !== fetchRef.current) {
|
if (fetchId !== fetchRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptions(
|
setOptions(
|
||||||
newOptions.data?.data?.resultList.map((item: any) => ({
|
newOptions.data?.resultList.map((item: any) => ({
|
||||||
label: item[filter.bizName],
|
label: item[filter.bizName],
|
||||||
value: item[filter.bizName],
|
value: item[filter.bizName],
|
||||||
})) || []
|
})) || []
|
||||||
@@ -76,7 +75,8 @@ const FilterItem: React.FC<Props> = ({ modelId, filters, filter, onFiltersChange
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={prefixCls}>
|
<span className={prefixCls}>
|
||||||
{typeof filter.value === 'string' || isArray(filter.value) ? (
|
{(typeof filter.value === 'string' || isArray(filter.value)) &&
|
||||||
|
(filter.operator === '=' || filter.operator === 'IN') ? (
|
||||||
<Select
|
<Select
|
||||||
bordered={false}
|
bordered={false}
|
||||||
value={filter.value}
|
value={filter.value}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { ReactNode } from 'react';
|
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, FilterItemType } from '../../common/type';
|
import { ChatContextType, FilterItemType } from '../../common/type';
|
||||||
import { CheckCircleFilled, InfoCircleOutlined } from '@ant-design/icons';
|
import { CheckCircleFilled } from '@ant-design/icons';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import SwicthEntity from './SwitchEntity';
|
import SwicthEntity from './SwitchEntity';
|
||||||
import Loading from './Loading';
|
import Loading from './Loading';
|
||||||
@@ -30,7 +30,7 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const prefixCls = `${PREFIX_CLS}-item`;
|
const prefixCls = `${PREFIX_CLS}-item`;
|
||||||
|
|
||||||
const getNode = (tipTitle: string, tipNode?: ReactNode, parseSucceed?: boolean) => {
|
const getNode = (tipTitle: ReactNode, tipNode?: ReactNode, parseSucceed?: boolean) => {
|
||||||
const contentContainerClass = classNames(`${prefixCls}-content-container`, {
|
const contentContainerClass = classNames(`${prefixCls}-content-container`, {
|
||||||
[`${prefixCls}-content-container-succeed`]: parseSucceed,
|
[`${prefixCls}-content-container-succeed`]: parseSucceed,
|
||||||
});
|
});
|
||||||
@@ -62,7 +62,6 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
|
|
||||||
const getTipNode = (parseInfo: ChatContextType, isOptions?: boolean, index?: number) => {
|
const getTipNode = (parseInfo: ChatContextType, isOptions?: boolean, index?: number) => {
|
||||||
const {
|
const {
|
||||||
modelId,
|
|
||||||
modelName,
|
modelName,
|
||||||
dateInfo,
|
dateInfo,
|
||||||
dimensionFilters,
|
dimensionFilters,
|
||||||
@@ -76,8 +75,6 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
nativeQuery,
|
nativeQuery,
|
||||||
} = parseInfo || {};
|
} = parseInfo || {};
|
||||||
|
|
||||||
const maxOptionCount = queryMode === 'DSL' ? 10 : MAX_OPTION_VALUES_COUNT;
|
|
||||||
|
|
||||||
const { startDate, endDate } = dateInfo || {};
|
const { startDate, endDate } = dateInfo || {};
|
||||||
const dimensionItems = dimensions?.filter(item => item.type === 'DIMENSION');
|
const dimensionItems = dimensions?.filter(item => item.type === 'DIMENSION');
|
||||||
const metric = metrics?.[0];
|
const metric = metrics?.[0];
|
||||||
@@ -92,44 +89,6 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
const fields =
|
const fields =
|
||||||
queryMode === 'ENTITY_DETAIL' ? dimensionItems?.concat(metrics || []) : dimensionItems;
|
queryMode === 'ENTITY_DETAIL' ? dimensionItems?.concat(metrics || []) : dimensionItems;
|
||||||
|
|
||||||
const getFilterContent = (filters: any) => {
|
|
||||||
return (
|
|
||||||
<div className={`${prefixCls}-tip-item-filter-content`}>
|
|
||||||
{filters.map((filter: any) => (
|
|
||||||
<div className={`${prefixCls}-tip-item-option`}>
|
|
||||||
<span>
|
|
||||||
<span className={`${prefixCls}-tip-item-filter-name`}>{filter.name}</span>
|
|
||||||
{filter.operator !== '=' && filter.operator !== 'IN'
|
|
||||||
? ` ${filter.operator} `
|
|
||||||
: ':'}
|
|
||||||
</span>
|
|
||||||
{queryMode !== 'DSL' && !filter.bizName?.includes('_id') ? (
|
|
||||||
<FilterItem
|
|
||||||
modelId={modelId}
|
|
||||||
filters={dimensionFilters}
|
|
||||||
filter={filter}
|
|
||||||
onFiltersChange={onFiltersChange}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span className={itemValueClass}>{filter.value}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getFiltersNode = () => {
|
|
||||||
return (
|
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
|
||||||
<div className={`${prefixCls}-tip-item-name`}>筛选条件:</div>
|
|
||||||
<div className={`${prefixCls}-tip-item-content`}>
|
|
||||||
{getFilterContent(dimensionFilters)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${prefixCls}-tip-content`}
|
className={`${prefixCls}-tip-content`}
|
||||||
@@ -147,7 +106,7 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{(queryMode.includes('ENTITY') || queryMode === 'DSL') &&
|
{(queryMode?.includes('ENTITY') || queryMode === 'DSL') &&
|
||||||
typeof entityId === 'string' &&
|
typeof entityId === 'string' &&
|
||||||
!!entityAlias &&
|
!!entityAlias &&
|
||||||
!!entityName ? (
|
!!entityName ? (
|
||||||
@@ -165,11 +124,11 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>数据模型:</div>
|
<div className={`${prefixCls}-tip-item-name`}>数据来源:</div>
|
||||||
<div className={itemValueClass}>{modelName}</div>
|
<div className={itemValueClass}>{modelName}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!queryMode.includes('ENTITY') && metric && (
|
{!queryMode?.includes('ENTITY') && metric && (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>指标:</div>
|
<div className={`${prefixCls}-tip-item-name`}>指标:</div>
|
||||||
<div className={itemValueClass}>{metric.name}</div>
|
<div className={itemValueClass}>{metric.name}</div>
|
||||||
@@ -199,24 +158,21 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className={itemValueClass}>
|
<div className={itemValueClass}>
|
||||||
{fields
|
{fields
|
||||||
.slice(0, maxOptionCount)
|
.slice(0, MAX_OPTION_VALUES_COUNT)
|
||||||
.map(field => field.name)
|
.map(field => field.name)
|
||||||
.join('、')}
|
.join('、')}
|
||||||
{fields.length > maxOptionCount && '...'}
|
{fields.length > MAX_OPTION_VALUES_COUNT && '...'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{[
|
{queryMode !== 'ENTITY_ID' &&
|
||||||
'METRIC_FILTER',
|
entityDimensions?.length > 0 &&
|
||||||
'METRIC_ENTITY',
|
entityDimensions.map(dimension => (
|
||||||
'ENTITY_DETAIL',
|
<div className={`${prefixCls}-tip-item`} key={dimension.itemId}>
|
||||||
'ENTITY_LIST_FILTER',
|
<div className={`${prefixCls}-tip-item-name`}>{dimension.name}:</div>
|
||||||
'ENTITY_ID',
|
<div className={itemValueClass}>{dimension.value}</div>
|
||||||
'DSL',
|
</div>
|
||||||
].includes(queryMode) &&
|
))}
|
||||||
dimensionFilters &&
|
|
||||||
dimensionFilters?.length > 0 &&
|
|
||||||
getFiltersNode()}
|
|
||||||
{queryMode === 'METRIC_ORDERBY' && aggType && aggType !== 'NONE' && (
|
{queryMode === 'METRIC_ORDERBY' && aggType && aggType !== 'NONE' && (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>聚合方式:</div>
|
<div className={`${prefixCls}-tip-item-name`}>聚合方式:</div>
|
||||||
@@ -230,7 +186,8 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const parseInfo = parseInfoOptions[0] || {};
|
const parseInfo = parseInfoOptions[0] || {};
|
||||||
const { properties, entity, entityInfo, elementMatches, queryMode } = parseInfo || {};
|
const { modelId, properties, entity, entityInfo, elementMatches, queryMode, dimensionFilters } =
|
||||||
|
parseInfo || {};
|
||||||
|
|
||||||
const { type } = properties || {};
|
const { type } = properties || {};
|
||||||
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
|
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
|
||||||
@@ -249,31 +206,71 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getFilterContent = (filters: any) => {
|
||||||
|
const itemValueClass = `${prefixCls}-tip-item-value`;
|
||||||
|
return (
|
||||||
|
<div className={`${prefixCls}-tip-item-filter-content`}>
|
||||||
|
{filters.map((filter: any) => (
|
||||||
|
<div className={`${prefixCls}-tip-item-option`} key={filter.name}>
|
||||||
|
<span>
|
||||||
|
<span className={`${prefixCls}-tip-item-filter-name`}>{filter.name}</span>
|
||||||
|
{filter.operator !== '=' && filter.operator !== 'IN' ? ` ${filter.operator} ` : ':'}
|
||||||
|
</span>
|
||||||
|
{/* {queryMode !== 'DSL' && !filter.bizName?.includes('_id') ? ( */}
|
||||||
|
{!filter.bizName?.includes('_id') ? (
|
||||||
|
<FilterItem
|
||||||
|
modelId={modelId}
|
||||||
|
filters={dimensionFilters}
|
||||||
|
filter={filter}
|
||||||
|
onFiltersChange={onFiltersChange}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span className={itemValueClass}>{filter.value}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFiltersNode = () => {
|
||||||
|
return (
|
||||||
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
|
<div className={`${prefixCls}-tip-item-name`}>筛选条件:</div>
|
||||||
|
<div className={`${prefixCls}-tip-item-content`}>{getFilterContent(dimensionFilters)}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const tipNode = (
|
const tipNode = (
|
||||||
<div className={`${prefixCls}-tip`}>
|
<div className={`${prefixCls}-tip`}>
|
||||||
{getTipNode(parseInfo)}
|
{getTipNode(parseInfo)}
|
||||||
{queryMode !== 'ENTITY_ID' && entityDimensions?.length > 0 && (
|
{[
|
||||||
<div className={`${prefixCls}-entity-info`}>
|
'METRIC_FILTER',
|
||||||
{entityDimensions.map(dimension => (
|
'METRIC_ENTITY',
|
||||||
<div className={`${prefixCls}-dimension-item`} key={dimension.itemId}>
|
'ENTITY_DETAIL',
|
||||||
<div className={`${prefixCls}-dimension-name`}>{dimension.name}:</div>
|
'ENTITY_LIST_FILTER',
|
||||||
<div className={`${prefixCls}-dimension-value`}>{dimension.value}</div>
|
'ENTITY_ID',
|
||||||
</div>
|
'DSL',
|
||||||
))}
|
].includes(queryMode) &&
|
||||||
</div>
|
dimensionFilters &&
|
||||||
)}
|
dimensionFilters?.length > 0 &&
|
||||||
{(!type || queryMode === 'DSL') && entityAlias && entityName && (
|
getFiltersNode()}
|
||||||
<div className={`${prefixCls}-switch-entity-tip`}>
|
|
||||||
<InfoCircleOutlined />
|
|
||||||
<div>
|
|
||||||
如果未匹配到您查询的{entityAlias},可点击上面的{entityAlias}名切换
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return getNode('意图解析结果', tipNode, true);
|
return getNode(
|
||||||
|
<div className={`${prefixCls}-title-bar`}>
|
||||||
|
意图解析
|
||||||
|
{(!type || queryMode === 'DSL') && entityAlias && entityAlias !== '厂牌' && entityName && (
|
||||||
|
<div className={`${prefixCls}-switch-entity-tip`}>
|
||||||
|
(如果未匹配到您查询的{entityAlias},可点击{entityAlias}名切换)
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>,
|
||||||
|
tipNode,
|
||||||
|
true
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ParseTip;
|
export default ParseTip;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { CheckCircleFilled, DownOutlined, UpOutlined } from '@ant-design/icons';
|
||||||
|
import { PREFIX_CLS } from '../../common/constants';
|
||||||
|
import { SimilarQuestionType } from '../../common/type';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
similarQuestions: SimilarQuestionType[];
|
||||||
|
defaultExpanded?: boolean;
|
||||||
|
onSelectQuestion: (question: SimilarQuestionType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SimilarQuestions: React.FC<Props> = ({
|
||||||
|
similarQuestions,
|
||||||
|
defaultExpanded,
|
||||||
|
onSelectQuestion,
|
||||||
|
}) => {
|
||||||
|
const [expanded, setExpanded] = useState(defaultExpanded || false);
|
||||||
|
|
||||||
|
const tipPrefixCls = `${PREFIX_CLS}-item`;
|
||||||
|
const prefixCls = `${PREFIX_CLS}-similar-questions`;
|
||||||
|
|
||||||
|
const onToggleExpanded = () => {
|
||||||
|
setExpanded(!expanded);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${tipPrefixCls}-parse-tip`}>
|
||||||
|
<div className={`${tipPrefixCls}-title-bar`}>
|
||||||
|
<CheckCircleFilled className={`${tipPrefixCls}-step-icon`} />
|
||||||
|
<div className={`${tipPrefixCls}-step-title`}>
|
||||||
|
推荐相似问题
|
||||||
|
<span className={`${prefixCls}-toggle-expand-btn`} onClick={onToggleExpanded}>
|
||||||
|
{expanded ? <UpOutlined /> : <DownOutlined />}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={prefixCls}>
|
||||||
|
{expanded && (
|
||||||
|
<div className={`${prefixCls}-content`}>
|
||||||
|
{similarQuestions.slice(0, 5).map((question, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`${prefixCls}-question`}
|
||||||
|
key={question.queryText}
|
||||||
|
onClick={() => {
|
||||||
|
onSelectQuestion(question);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{index + 1}. {question.queryText}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SimilarQuestions;
|
||||||
116
webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx
Normal file
116
webapp/packages/chat-sdk/src/components/ChatItem/SqlItem.tsx
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { format } from 'sql-formatter';
|
||||||
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
|
import { solarizedlight } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { PREFIX_CLS } from '../../common/constants';
|
||||||
|
import { CheckCircleFilled, UpOutlined } from '@ant-design/icons';
|
||||||
|
import { SqlInfoType } from '../../common/type';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
integrateSystem?: string;
|
||||||
|
sqlInfo: SqlInfoType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SqlItem: React.FC<Props> = ({ integrateSystem, sqlInfo }) => {
|
||||||
|
const [sqlType, setSqlType] = useState('');
|
||||||
|
|
||||||
|
const tipPrefixCls = `${PREFIX_CLS}-item`;
|
||||||
|
const prefixCls = `${PREFIX_CLS}-sql-item`;
|
||||||
|
|
||||||
|
const handleCopy = (text, result) => {
|
||||||
|
result ? message.success('复制SQL成功', 1) : message.error('复制SQL失败', 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCollapse = () => {
|
||||||
|
setSqlType('');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!sqlInfo.llmParseSql && !sqlInfo.logicSql && !sqlInfo.querySql) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${tipPrefixCls}-parse-tip`}>
|
||||||
|
<div className={`${tipPrefixCls}-title-bar`}>
|
||||||
|
<CheckCircleFilled className={`${tipPrefixCls}-step-icon`} />
|
||||||
|
<div className={`${tipPrefixCls}-step-title`}>
|
||||||
|
SQL生成
|
||||||
|
{sqlType && (
|
||||||
|
<span className={`${prefixCls}-toggle-expand-btn`} onClick={onCollapse}>
|
||||||
|
<UpOutlined />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={`${prefixCls}-sql-options`}>
|
||||||
|
{sqlInfo.llmParseSql && (
|
||||||
|
<div
|
||||||
|
className={`${prefixCls}-sql-option ${
|
||||||
|
sqlType === 'llmParseSql' ? `${prefixCls}-sql-option-active` : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setSqlType(sqlType === 'llmParseSql' ? '' : 'llmParseSql');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
LLM解析SQL
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{sqlInfo.logicSql && (
|
||||||
|
<div
|
||||||
|
className={`${prefixCls}-sql-option ${
|
||||||
|
sqlType === 'logicSql' ? `${prefixCls}-sql-option-active` : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setSqlType(sqlType === 'logicSql' ? '' : 'logicSql');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
逻辑SQL
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{sqlInfo.querySql && (
|
||||||
|
<div
|
||||||
|
className={`${prefixCls}-sql-option ${
|
||||||
|
sqlType === 'querySql' ? `${prefixCls}-sql-option-active` : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setSqlType(sqlType === 'querySql' ? '' : 'querySql');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
物理SQL
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`${prefixCls} ${
|
||||||
|
!window.location.pathname.includes('/chat') &&
|
||||||
|
integrateSystem &&
|
||||||
|
integrateSystem !== 'wiki'
|
||||||
|
? `${prefixCls}-copilot`
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{sqlType && (
|
||||||
|
<>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
className={`${prefixCls}-code`}
|
||||||
|
language="sql"
|
||||||
|
style={solarizedlight}
|
||||||
|
>
|
||||||
|
{format(sqlInfo[sqlType])}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
<CopyToClipboard
|
||||||
|
text={format(sqlInfo[sqlType])}
|
||||||
|
onCopy={(text, result) => handleCopy(text, result)}
|
||||||
|
>
|
||||||
|
<button className={`${prefixCls}-copy-btn`}>复制代码</button>
|
||||||
|
</CopyToClipboard>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SqlItem;
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
import { ChatContextType, FilterItemType, MsgDataType, ParseStateEnum } from '../../common/type';
|
import {
|
||||||
|
ChatContextType,
|
||||||
|
FilterItemType,
|
||||||
|
MsgDataType,
|
||||||
|
ParseStateEnum,
|
||||||
|
SimilarQuestionType,
|
||||||
|
} from '../../common/type';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { chatExecute, chatParse, queryData, switchEntity } from '../../service';
|
import { chatExecute, chatParse, queryData, switchEntity } from '../../service';
|
||||||
import { PARSE_ERROR_TIP, PREFIX_CLS, SEARCH_EXCEPTION_TIP } from '../../common/constants';
|
import { PARSE_ERROR_TIP, PREFIX_CLS, SEARCH_EXCEPTION_TIP } from '../../common/constants';
|
||||||
@@ -8,6 +14,8 @@ import ExecuteItem from './ExecuteItem';
|
|||||||
import { isMobile } from '../../utils/utils';
|
import { isMobile } from '../../utils/utils';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Tools from '../Tools';
|
import Tools from '../Tools';
|
||||||
|
import SqlItem from './SqlItem';
|
||||||
|
import SimilarQuestionItem from './SimilarQuestionItem';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
msg: string;
|
msg: string;
|
||||||
@@ -17,11 +25,13 @@ type Props = {
|
|||||||
filter?: any[];
|
filter?: any[];
|
||||||
isLastMessage?: boolean;
|
isLastMessage?: boolean;
|
||||||
msgData?: MsgDataType;
|
msgData?: MsgDataType;
|
||||||
isHistory?: boolean;
|
|
||||||
triggerResize?: boolean;
|
triggerResize?: boolean;
|
||||||
parseOptions?: ChatContextType[];
|
parseOptions?: ChatContextType[];
|
||||||
|
isDeveloper?: boolean;
|
||||||
|
integrateSystem?: string;
|
||||||
onMsgDataLoaded?: (data: MsgDataType, valid: boolean) => void;
|
onMsgDataLoaded?: (data: MsgDataType, valid: boolean) => void;
|
||||||
onUpdateMessageScroll?: () => void;
|
onUpdateMessageScroll?: () => void;
|
||||||
|
onSendMsg?: (msg: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChatItem: React.FC<Props> = ({
|
const ChatItem: React.FC<Props> = ({
|
||||||
@@ -31,12 +41,14 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
agentId,
|
agentId,
|
||||||
filter,
|
filter,
|
||||||
isLastMessage,
|
isLastMessage,
|
||||||
isHistory,
|
|
||||||
triggerResize,
|
triggerResize,
|
||||||
msgData,
|
msgData,
|
||||||
parseOptions,
|
parseOptions,
|
||||||
|
isDeveloper,
|
||||||
|
integrateSystem,
|
||||||
onMsgDataLoaded,
|
onMsgDataLoaded,
|
||||||
onUpdateMessageScroll,
|
onUpdateMessageScroll,
|
||||||
|
onSendMsg,
|
||||||
}) => {
|
}) => {
|
||||||
const [data, setData] = useState<MsgDataType>();
|
const [data, setData] = useState<MsgDataType>();
|
||||||
const [parseLoading, setParseLoading] = useState(false);
|
const [parseLoading, setParseLoading] = useState(false);
|
||||||
@@ -47,6 +59,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
const [executeTip, setExecuteTip] = useState('');
|
const [executeTip, setExecuteTip] = useState('');
|
||||||
const [executeMode, setExecuteMode] = useState(false);
|
const [executeMode, setExecuteMode] = useState(false);
|
||||||
const [entitySwitchLoading, setEntitySwitchLoading] = useState(false);
|
const [entitySwitchLoading, setEntitySwitchLoading] = useState(false);
|
||||||
|
const [similarQuestions, setSimilarQuestions] = useState<SimilarQuestionType[]>([]);
|
||||||
|
|
||||||
const [chartIndex, setChartIndex] = useState(0);
|
const [chartIndex, setChartIndex] = useState(0);
|
||||||
|
|
||||||
@@ -79,13 +92,13 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
setExecuteMode(true);
|
setExecuteMode(true);
|
||||||
setExecuteLoading(true);
|
setExecuteLoading(true);
|
||||||
try {
|
try {
|
||||||
const { data } = await chatExecute(msg, conversationId!, parseInfoValue);
|
const res: any = await chatExecute(msg, conversationId!, parseInfoValue);
|
||||||
setExecuteLoading(false);
|
setExecuteLoading(false);
|
||||||
const valid = updateData(data);
|
const valid = updateData(res);
|
||||||
if (onMsgDataLoaded) {
|
if (onMsgDataLoaded) {
|
||||||
onMsgDataLoaded(
|
onMsgDataLoaded(
|
||||||
{
|
{
|
||||||
...data.data,
|
...res.data,
|
||||||
chatContext: parseInfoValue,
|
chatContext: parseInfoValue,
|
||||||
},
|
},
|
||||||
valid
|
valid
|
||||||
@@ -97,12 +110,13 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSendMsg = async () => {
|
const sendMsg = async () => {
|
||||||
setParseLoading(true);
|
setParseLoading(true);
|
||||||
const { data: parseData } = 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, queryId } = data || {};
|
const { state, selectedParses, queryId, similarSolvedQuery } = data || {};
|
||||||
|
setSimilarQuestions(similarSolvedQuery || []);
|
||||||
if (
|
if (
|
||||||
code !== 200 ||
|
code !== 200 ||
|
||||||
state === ParseStateEnum.FAILED ||
|
state === ParseStateEnum.FAILED ||
|
||||||
@@ -115,7 +129,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
if (onUpdateMessageScroll) {
|
if (onUpdateMessageScroll) {
|
||||||
onUpdateMessageScroll();
|
onUpdateMessageScroll();
|
||||||
}
|
}
|
||||||
const parseInfos = selectedParses.map(item => ({
|
const parseInfos = selectedParses.map((item: any) => ({
|
||||||
...item,
|
...item,
|
||||||
queryId,
|
queryId,
|
||||||
}));
|
}));
|
||||||
@@ -126,15 +140,17 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data !== undefined || parseOptions !== undefined || executeTip !== '') {
|
if (data !== undefined || parseOptions !== undefined || executeTip !== '' || parseLoading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msgData) {
|
if (msgData) {
|
||||||
setParseInfoOptions([msgData.chatContext]);
|
const parseInfoValue = { ...msgData.chatContext, queryId: msgData.queryId };
|
||||||
|
setParseInfoOptions([parseInfoValue]);
|
||||||
|
setParseInfo(parseInfoValue);
|
||||||
setExecuteMode(true);
|
setExecuteMode(true);
|
||||||
updateData({ code: 200, data: msgData, msg: 'success' });
|
updateData({ code: 200, data: msgData, msg: 'success' });
|
||||||
} else if (msg) {
|
} else if (msg) {
|
||||||
onSendMsg();
|
sendMsg();
|
||||||
}
|
}
|
||||||
}, [msg, msgData]);
|
}, [msg, msgData]);
|
||||||
|
|
||||||
@@ -142,19 +158,27 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
setEntitySwitchLoading(true);
|
setEntitySwitchLoading(true);
|
||||||
const res = await switchEntity(entityId, data?.chatContext?.modelId, conversationId || 0);
|
const res = await switchEntity(entityId, data?.chatContext?.modelId, conversationId || 0);
|
||||||
setEntitySwitchLoading(false);
|
setEntitySwitchLoading(false);
|
||||||
setData(res.data.data);
|
setData(res.data);
|
||||||
const { chatContext } = res.data.data;
|
const { chatContext } = res.data;
|
||||||
setParseInfo(chatContext);
|
setParseInfo(chatContext);
|
||||||
setParseInfoOptions([chatContext]);
|
setParseInfoOptions([chatContext]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFiltersChange = async (dimensionFilters: FilterItemType[]) => {
|
const onFiltersChange = async (dimensionFilters: FilterItemType[]) => {
|
||||||
setEntitySwitchLoading(true);
|
setEntitySwitchLoading(true);
|
||||||
const chatContextValue = { ...(parseInfoOptions[0] || {}), dimensionFilters };
|
const { dimensions, metrics, dateInfo, id, queryId } = parseInfoOptions[0] || {};
|
||||||
|
const chatContextValue = {
|
||||||
|
dimensions,
|
||||||
|
metrics,
|
||||||
|
dateInfo,
|
||||||
|
dimensionFilters,
|
||||||
|
parseId: id,
|
||||||
|
queryId,
|
||||||
|
};
|
||||||
const res: any = await queryData(chatContextValue);
|
const res: any = await queryData(chatContextValue);
|
||||||
setEntitySwitchLoading(false);
|
setEntitySwitchLoading(false);
|
||||||
const resChatContext = res.data?.data?.chatContext;
|
const resChatContext = res.data?.chatContext;
|
||||||
setData({ ...(res.data?.data || {}), chatContext: resChatContext || chatContextValue });
|
setData({ ...(res.data || {}), chatContext: resChatContext || chatContextValue });
|
||||||
setParseInfo(resChatContext || chatContextValue);
|
setParseInfo(resChatContext || chatContextValue);
|
||||||
setParseInfoOptions([resChatContext || chatContextValue]);
|
setParseInfoOptions([resChatContext || chatContextValue]);
|
||||||
};
|
};
|
||||||
@@ -167,6 +191,10 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSelectQuestion = (question: SimilarQuestionType) => {
|
||||||
|
onSendMsg?.(question.queryText);
|
||||||
|
};
|
||||||
|
|
||||||
const contentClass = classNames(`${prefixCls}-content`, {
|
const contentClass = classNames(`${prefixCls}-content`, {
|
||||||
[`${prefixCls}-content-mobile`]: isMobile,
|
[`${prefixCls}-content-mobile`]: isMobile,
|
||||||
});
|
});
|
||||||
@@ -189,17 +217,36 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
onSwitchEntity={onSwitchEntity}
|
onSwitchEntity={onSwitchEntity}
|
||||||
onFiltersChange={onFiltersChange}
|
onFiltersChange={onFiltersChange}
|
||||||
/>
|
/>
|
||||||
{executeMode && (
|
{parseTip && similarQuestions.length > 0 && (
|
||||||
<ExecuteItem
|
<SimilarQuestionItem
|
||||||
queryId={parseInfo?.queryId}
|
similarQuestions={similarQuestions}
|
||||||
executeLoading={executeLoading}
|
defaultExpanded
|
||||||
entitySwitchLoading={entitySwitchLoading}
|
onSelectQuestion={onSelectQuestion}
|
||||||
executeTip={executeTip}
|
|
||||||
chartIndex={chartIndex}
|
|
||||||
data={data}
|
|
||||||
triggerResize={triggerResize}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{executeMode && (
|
||||||
|
<>
|
||||||
|
{parseInfoOptions?.[0]?.sqlInfo && isDeveloper && integrateSystem !== 'c2' && (
|
||||||
|
<SqlItem integrateSystem={integrateSystem} sqlInfo={parseInfoOptions[0].sqlInfo} />
|
||||||
|
)}
|
||||||
|
{similarQuestions.length > 0 && (
|
||||||
|
<SimilarQuestionItem
|
||||||
|
similarQuestions={similarQuestions}
|
||||||
|
defaultExpanded={executeTip !== ''}
|
||||||
|
onSelectQuestion={onSelectQuestion}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<ExecuteItem
|
||||||
|
queryId={parseInfo?.queryId}
|
||||||
|
executeLoading={executeLoading}
|
||||||
|
entitySwitchLoading={entitySwitchLoading}
|
||||||
|
executeTip={executeTip}
|
||||||
|
chartIndex={chartIndex}
|
||||||
|
data={data}
|
||||||
|
triggerResize={triggerResize}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isMetricCard && data && (
|
{!isMetricCard && data && (
|
||||||
<Tools data={data} scoreValue={undefined} isLastMessage={isLastMessage} />
|
<Tools data={data} scoreValue={undefined} isLastMessage={isLastMessage} />
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
@chat-item-prefix-cls: ~'@{supersonic-chat-prefix}-item';
|
@chat-item-prefix-cls: ~'@{supersonic-chat-prefix}-item';
|
||||||
@filter-item-prefix-cls: ~'@{supersonic-chat-prefix}-filter-item';
|
@filter-item-prefix-cls: ~'@{supersonic-chat-prefix}-filter-item';
|
||||||
|
@sql-item-prefix-cls: ~'@{supersonic-chat-prefix}-sql-item';
|
||||||
|
@similar-questions-prefix-cls: ~'@{supersonic-chat-prefix}-similar-questions';
|
||||||
|
|
||||||
.@{chat-item-prefix-cls} {
|
.@{chat-item-prefix-cls} {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -17,7 +19,6 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
// border-radius: 50%;
|
|
||||||
background-color: var(--text-color);
|
background-color: var(--text-color);
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -124,8 +125,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
column-gap: 6px;
|
column-gap: 6px;
|
||||||
margin-top: 4px;
|
color: var(--text-color-fourth);
|
||||||
color: var(--text-color-third);
|
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
&-tip {
|
&-tip {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
row-gap: 6px;
|
row-gap: 10px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
color: var(--text-color-third);
|
color: var(--text-color-third);
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
row-gap: 6px;
|
row-gap: 10px;
|
||||||
column-gap: 12px;
|
column-gap: 12px;
|
||||||
color: var(--text-color-third);
|
color: var(--text-color-third);
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,6 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
row-gap: 6px;
|
row-gap: 6px;
|
||||||
column-gap: 12px;
|
column-gap: 12px;
|
||||||
margin-top: 4px;
|
|
||||||
color: var(--text-color-third);
|
color: var(--text-color-third);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
@@ -325,4 +324,93 @@
|
|||||||
color: var(--chat-blue);
|
color: var(--chat-blue);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.@{sql-item-prefix-cls} {
|
||||||
|
position: relative;
|
||||||
|
margin: 2px 0 2px 7px;
|
||||||
|
padding: 2px 0 8px 18px;
|
||||||
|
border-left: 1px solid var(--green);
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&-toggle-expand-btn {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: var(--text-color-fourth);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-sql-options {
|
||||||
|
margin-left: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 13px;
|
||||||
|
color: var(--text-color-third);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-sql-option {
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1px 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--chat-blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-sql-option-active {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: var(--chat-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-code {
|
||||||
|
margin-top: 10px !important;
|
||||||
|
padding: 6px 14px 8px !important;
|
||||||
|
border: 1px solid var(--border-color-base) !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
background: #f5f8fb !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-copy-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
right: 20px;
|
||||||
|
background: transparent !important;
|
||||||
|
border: 0 !important;
|
||||||
|
color: var(--chat-blue);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{sql-item-prefix-cls}-copilot {
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{similar-questions-prefix-cls} {
|
||||||
|
position: relative;
|
||||||
|
margin: 2px 0 2px 7px;
|
||||||
|
padding: 2px 0 8px 18px;
|
||||||
|
border-left: 1px solid var(--green);
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&-toggle-expand-btn {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: var(--text-color-fourth);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 12px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-question {
|
||||||
|
width: fit-content;
|
||||||
|
color: var(--chat-blue);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const Message: React.FC<Props> = ({
|
|||||||
<div className={`${prefixCls}-info-bar`}>
|
<div className={`${prefixCls}-info-bar`}>
|
||||||
<div className={`${prefixCls}-main-entity-info`}>
|
<div className={`${prefixCls}-main-entity-info`}>
|
||||||
<div className={`${prefixCls}-info-item`}>
|
<div className={`${prefixCls}-info-item`}>
|
||||||
<div className={`${prefixCls}-info-name`}>数据模型:</div>
|
<div className={`${prefixCls}-info-name`}>数据来源:</div>
|
||||||
<div className={`${prefixCls}-info-value`}>{modelName}</div>
|
<div className={`${prefixCls}-info-value`}>{modelName}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${prefixCls}-info-item`}>
|
<div className={`${prefixCls}-info-item`}>
|
||||||
|
|||||||
@@ -19,33 +19,7 @@ const Text: React.FC<Props> = ({ columns, referenceColumn, dataSource }) => {
|
|||||||
|
|
||||||
const initData = () => {
|
const initData = () => {
|
||||||
let textValue = dataSource[0][columns[0].nameEn];
|
let textValue = dataSource[0][columns[0].nameEn];
|
||||||
let htmlCodeValue: string;
|
setText(textValue === undefined ? '暂无数据,如有疑问请联系管理员' : textValue);
|
||||||
const match = textValue.match(/```html([\s\S]*?)```/);
|
|
||||||
htmlCodeValue = match && match[1].trim();
|
|
||||||
if (htmlCodeValue) {
|
|
||||||
textValue = textValue.replace(/```html([\s\S]*?)```/, '');
|
|
||||||
}
|
|
||||||
let scriptCode: string;
|
|
||||||
let scriptSrc: string;
|
|
||||||
if (htmlCodeValue) {
|
|
||||||
scriptSrc = htmlCodeValue.match(/<script src="([\s\S]*?)"><\/script>/)?.[1] || '';
|
|
||||||
scriptCode =
|
|
||||||
htmlCodeValue.match(/<script type="text\/javascript">([\s\S]*?)<\/script>/)?.[1] || '';
|
|
||||||
if (scriptSrc) {
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.src = scriptSrc;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
}
|
|
||||||
if (scriptCode) {
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.innerHTML = scriptCode;
|
|
||||||
setTimeout(() => {
|
|
||||||
document.body.appendChild(script);
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setText(textValue);
|
|
||||||
setHtmlCode(htmlCodeValue);
|
|
||||||
if (referenceColumn) {
|
if (referenceColumn) {
|
||||||
const referenceDataValue = dataSource[0][referenceColumn.nameEn];
|
const referenceDataValue = dataSource[0][referenceColumn.nameEn];
|
||||||
setReferenceData(referenceDataValue || []);
|
setReferenceData(referenceDataValue || []);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { CLS_PREFIX } from '../../../common/constants';
|
import { CLS_PREFIX } from '../../../common/constants';
|
||||||
import { MsgDataType } from '../../../common/type';
|
import { MsgDataType } from '../../../common/type';
|
||||||
import { isProd } from '../../../utils/utils';
|
import { getToken, isProd } from '../../../utils/utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
@@ -89,10 +89,8 @@ const WebPage: React.FC<Props> = ({ id, data }) => {
|
|||||||
);
|
);
|
||||||
urlValue = urlValue.replace(
|
urlValue = urlValue.replace(
|
||||||
'?',
|
'?',
|
||||||
`?miniProgram=true&reportName=${name}&filterData=${filterData}&`
|
`?token=${getToken()}&miniProgram=true&reportName=${name}&filterData=${filterData}&`
|
||||||
);
|
);
|
||||||
urlValue =
|
|
||||||
!isProd() && !urlValue.includes('http') ? `http://s2.tmeoa.com${urlValue}` : urlValue;
|
|
||||||
} else {
|
} else {
|
||||||
const params = Object.keys(valueParams || {}).map(key => `${key}=${valueParams[key]}`);
|
const params = Object.keys(valueParams || {}).map(key => `${key}=${valueParams[key]}`);
|
||||||
if (params.length > 0) {
|
if (params.length > 0) {
|
||||||
@@ -103,7 +101,6 @@ const WebPage: React.FC<Props> = ({ id, data }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// onReportLoaded(heightValue + 190);
|
|
||||||
setPluginUrl(urlValue);
|
setPluginUrl(urlValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,7 +109,6 @@ const WebPage: React.FC<Props> = ({ id, data }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// <div className={prefixCls} style={{ height }}>
|
|
||||||
<iframe
|
<iframe
|
||||||
id={`reportIframe_${id}`}
|
id={`reportIframe_${id}`}
|
||||||
name={`reportIframe_${id}`}
|
name={`reportIframe_${id}`}
|
||||||
@@ -121,7 +117,6 @@ const WebPage: React.FC<Props> = ({ id, data }) => {
|
|||||||
title="reportIframe"
|
title="reportIframe"
|
||||||
allowFullScreen
|
allowFullScreen
|
||||||
/>
|
/>
|
||||||
// </div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ import DrillDownDimensions from '../DrillDownDimensions';
|
|||||||
import MetricOptions from '../MetricOptions';
|
import MetricOptions from '../MetricOptions';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
queryId?: number;
|
||||||
data: MsgDataType;
|
data: MsgDataType;
|
||||||
chartIndex: number;
|
chartIndex: number;
|
||||||
triggerResize?: boolean;
|
triggerResize?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize }) => {
|
||||||
const { queryColumns, queryResults, chatContext, queryMode } = data || {};
|
const { queryColumns, queryResults, chatContext, queryMode } = data || {};
|
||||||
const { dimensionFilters, elementMatches } = chatContext || {};
|
const { dimensionFilters, elementMatches } = chatContext || {};
|
||||||
|
|
||||||
@@ -127,14 +128,16 @@ const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
|||||||
|
|
||||||
const onLoadData = async (value: any) => {
|
const onLoadData = async (value: any) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { data } = await queryData({
|
const res: any = await queryData({
|
||||||
...chatContext,
|
// ...chatContext,
|
||||||
|
queryId,
|
||||||
|
parseId: chatContext.id,
|
||||||
...value,
|
...value,
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (data.code === 200) {
|
if (res.code === 200) {
|
||||||
updateColummns(data.data?.queryColumns || []);
|
updateColummns(res.data?.queryColumns || []);
|
||||||
setDataSource(data.data?.queryResults || []);
|
setDataSource(res.data?.queryResults || []);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const DrillDownDimensions: React.FC<Props> = ({
|
|||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
const res = await queryDrillDownDimensions(modelId);
|
const res = await queryDrillDownDimensions(modelId);
|
||||||
setDimensions(
|
setDimensions(
|
||||||
res.data.data.dimensions
|
res.data.dimensions
|
||||||
.filter(
|
.filter(
|
||||||
dimension =>
|
dimension =>
|
||||||
!dimensionFilters?.some(filter => filter.name === dimension.name) &&
|
!dimensionFilters?.some(filter => filter.name === dimension.name) &&
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createFromIconfontCN } from '@ant-design/icons';
|
import { createFromIconfontCN } from '@ant-design/icons';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_4120566_x5c4www9bqm.js',
|
scriptUrl: '//at.alicdn.com/t/c/font_4120566_46xw04fpzii.js',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const RecommendOptions: React.FC<Props> = ({ entityId, modelId, modelName, onSel
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await queryEntities(entityId, modelId);
|
const res = await queryEntities(entityId, modelId);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setData(res.data.data);
|
setData(res.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
14
webapp/packages/chat-sdk/src/demo/ChatDemo.tsx
Normal file
14
webapp/packages/chat-sdk/src/demo/ChatDemo.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import Chat from '../Chat';
|
||||||
|
import styles from './style.module.less';
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const ChatDemo: React.FC<Props> = ({}) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.chatDemo}>
|
||||||
|
<Chat isDeveloper />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChatDemo;
|
||||||
50
webapp/packages/chat-sdk/src/demo/CopilotDemo.tsx
Normal file
50
webapp/packages/chat-sdk/src/demo/CopilotDemo.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { Button, Space } from 'antd';
|
||||||
|
import styles from './style.module.less';
|
||||||
|
import Copilot from '../Copilot';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
|
||||||
|
const buttonParams = [
|
||||||
|
{
|
||||||
|
msg: '周杰伦 艺人趋势解读',
|
||||||
|
agentId: 8,
|
||||||
|
modelId: 23,
|
||||||
|
filters: [{ bizName: 'singer_id', elementID: 283, value: 4558 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
msg: '林俊杰 艺人趋势解读',
|
||||||
|
agentId: 8,
|
||||||
|
modelId: 23,
|
||||||
|
filters: [{ bizName: 'singer_id', elementID: 283, value: 4286 }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const CopilotDemo = () => {
|
||||||
|
const copilotRef = useRef<any>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.copilotDemo}>
|
||||||
|
<Space>
|
||||||
|
{buttonParams.map(params => (
|
||||||
|
<Button
|
||||||
|
key={params.msg}
|
||||||
|
onClick={() => {
|
||||||
|
copilotRef?.current?.sendCopilotMsg(params);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{params.msg}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
<Copilot
|
||||||
|
// token={localStorage.getItem('SUPERSONIC_TOKEN') || ''}
|
||||||
|
// agentIds={[8]}
|
||||||
|
isDeveloper
|
||||||
|
// integrateSystem="c2"
|
||||||
|
ref={copilotRef}
|
||||||
|
// noInput
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CopilotDemo;
|
||||||
@@ -8,4 +8,8 @@
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chatDemo {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import './styles/index.less';
|
import './styles/index.less';
|
||||||
|
|
||||||
// import React from 'react';
|
|
||||||
// import ReactDOM from 'react-dom/client';
|
// import ReactDOM from 'react-dom/client';
|
||||||
// import Chat from './demo/Chat';
|
// import Chat from './demo/Chat';
|
||||||
|
// import ChatDemo from './demo/ChatDemo';
|
||||||
|
// import CopilotDemo from './demo/CopilotDemo';
|
||||||
// const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
// const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
||||||
|
// root.render(<ChatDemo />);
|
||||||
|
|
||||||
// root.render(
|
export { default as Chat } from './Chat';
|
||||||
// <React.StrictMode>
|
|
||||||
// <Chat />
|
export { default as Copilot } from './Copilot';
|
||||||
// </React.StrictMode>
|
|
||||||
// );
|
|
||||||
|
|
||||||
export { default as ChatMsg } from './components/ChatMsg';
|
export { default as ChatMsg } from './components/ChatMsg';
|
||||||
|
|
||||||
@@ -33,6 +32,7 @@ export type {
|
|||||||
FilterItemType,
|
FilterItemType,
|
||||||
HistoryType,
|
HistoryType,
|
||||||
HistoryMsgItemType,
|
HistoryMsgItemType,
|
||||||
|
SendMsgParamsType,
|
||||||
} from './common/type';
|
} from './common/type';
|
||||||
|
|
||||||
export { getHistoryMsg, searchRecommend, queryContext } from './service';
|
export { getHistoryMsg, searchRecommend, queryContext } from './service';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { getToken } from '../utils/utils';
|
|||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const axiosInstance: AxiosInstance = axios.create({
|
const axiosInstance: AxiosInstance = axios.create({
|
||||||
// 设置基本URL,所有请求都会使用这个URL作为前缀
|
// 设置基本URL,所有请求都会使用这个URL作为前缀
|
||||||
baseURL: '',
|
baseURL: localStorage.getItem('SUPERSONIC_CHAT_API_URL') || '',
|
||||||
// 设置请求超时时间(毫秒)
|
// 设置请求超时时间(毫秒)
|
||||||
timeout: 120000,
|
timeout: 120000,
|
||||||
// 设置请求头
|
// 设置请求头
|
||||||
@@ -19,7 +19,7 @@ axiosInstance.interceptors.request.use(
|
|||||||
(config: any) => {
|
(config: any) => {
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
if (token && config?.headers) {
|
if (token && config?.headers) {
|
||||||
config.headers.Auth = `Bearer ${token}`;
|
// config.headers.Auth = `Bearer ${token}`;
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
@@ -33,18 +33,18 @@ axiosInstance.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
(response: any) => {
|
(response: any) => {
|
||||||
const redirect = response.headers.get('redirect');
|
const redirect = response.headers['redirect'];
|
||||||
if (redirect === 'REDIRECT') {
|
if (redirect === 'REDIRECT') {
|
||||||
let win: any = window;
|
let win: any = window;
|
||||||
while (win !== win.top) {
|
while (win !== win.top) {
|
||||||
win = win.top;
|
win = win.top;
|
||||||
}
|
}
|
||||||
const contextpath = response.headers.get('contextpath');
|
const contextpath = response.headers['contextpath'];
|
||||||
win.location.href =
|
win.location.href =
|
||||||
contextpath?.substring(0, contextpath?.indexOf('&')) +
|
contextpath?.substring(0, contextpath?.indexOf('&')) +
|
||||||
`&redirect_uri=${encodeURIComponent(`http://${win.location.host}`)}`;
|
`&redirect_uri=${encodeURIComponent(`http://${win.location.host}`)}`;
|
||||||
}
|
}
|
||||||
return response;
|
return response.data;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// 对响应错误进行处理
|
// 对响应错误进行处理
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import axios from './axiosInstance';
|
import axios from './axiosInstance';
|
||||||
import { ChatContextType, DrillDownDimensionType, HistoryType, MsgDataType, ParseDataType, SearchRecommendItem } from '../common/type';
|
import { ChatContextType, DrillDownDimensionType, HistoryType, MsgDataType, ParseDataType, SearchRecommendItem } from '../common/type';
|
||||||
|
|
||||||
const DEFAULT_CHAT_ID = 12009993;
|
const DEFAULT_CHAT_ID = 0;
|
||||||
|
|
||||||
const prefix = '/api';
|
const prefix = '/api';
|
||||||
|
|
||||||
export function searchRecommend(queryText: string, chatId?: number, modelId?: number, agentId?: number) {
|
export function searchRecommend(queryText: string, chatId?: number, modelId?: number, agentId?: number) {
|
||||||
return axios.post<Result<SearchRecommendItem[]>>(`${prefix}/chat/query/search`, {
|
return axios.post<SearchRecommendItem[]>(`${prefix}/chat/query/search`, {
|
||||||
queryText,
|
queryText,
|
||||||
chatId: chatId || DEFAULT_CHAT_ID,
|
chatId: chatId || DEFAULT_CHAT_ID,
|
||||||
modelId,
|
modelId,
|
||||||
@@ -15,7 +15,7 @@ export function searchRecommend(queryText: string, chatId?: number, modelId?: nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function chatQuery(queryText: string, chatId?: number, modelId?: number, filters?: any[]) {
|
export function chatQuery(queryText: string, chatId?: number, modelId?: number, filters?: any[]) {
|
||||||
return axios.post<Result<MsgDataType>>(`${prefix}/chat/query/query`, {
|
return axios.post<MsgDataType>(`${prefix}/chat/query/query`, {
|
||||||
queryText,
|
queryText,
|
||||||
chatId: chatId || DEFAULT_CHAT_ID,
|
chatId: chatId || DEFAULT_CHAT_ID,
|
||||||
modelId,
|
modelId,
|
||||||
@@ -26,7 +26,7 @@ export function chatQuery(queryText: string, chatId?: number, modelId?: number,
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function chatParse(queryText: string, chatId?: number, modelId?: number, agentId?: number, filters?: any[]) {
|
export function chatParse(queryText: string, chatId?: number, modelId?: number, agentId?: number, filters?: any[]) {
|
||||||
return axios.post<Result<ParseDataType>>(`${prefix}/chat/query/parse`, {
|
return axios.post<ParseDataType>(`${prefix}/chat/query/parse`, {
|
||||||
queryText,
|
queryText,
|
||||||
chatId: chatId || DEFAULT_CHAT_ID,
|
chatId: chatId || DEFAULT_CHAT_ID,
|
||||||
modelId,
|
modelId,
|
||||||
@@ -38,7 +38,7 @@ export function chatParse(queryText: string, chatId?: number, modelId?: number,
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function chatExecute(queryText: string, chatId: number, parseInfo: ChatContextType ) {
|
export function chatExecute(queryText: string, chatId: number, parseInfo: ChatContextType ) {
|
||||||
return axios.post<Result<MsgDataType>>(`${prefix}/chat/query/execute`, {
|
return axios.post<MsgDataType>(`${prefix}/chat/query/execute`, {
|
||||||
queryText,
|
queryText,
|
||||||
chatId: chatId || DEFAULT_CHAT_ID,
|
chatId: chatId || DEFAULT_CHAT_ID,
|
||||||
queryId: parseInfo.queryId,
|
queryId: parseInfo.queryId,
|
||||||
@@ -47,7 +47,7 @@ export function chatExecute(queryText: string, chatId: number, parseInfo: ChatC
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function switchEntity(entityId: string, modelId?: number, chatId?: number) {
|
export function switchEntity(entityId: string, modelId?: number, chatId?: number) {
|
||||||
return axios.post<Result<any>>(`${prefix}/chat/query/switchQuery`, {
|
return axios.post<any>(`${prefix}/chat/query/switchQuery`, {
|
||||||
queryText: entityId,
|
queryText: entityId,
|
||||||
modelId,
|
modelId,
|
||||||
chatId: chatId || DEFAULT_CHAT_ID,
|
chatId: chatId || DEFAULT_CHAT_ID,
|
||||||
@@ -55,46 +55,46 @@ export function switchEntity(entityId: string, modelId?: number, chatId?: number
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function queryData(chatContext: Partial<ChatContextType>) {
|
export function queryData(chatContext: Partial<ChatContextType>) {
|
||||||
return axios.post<Result<MsgDataType>>(`${prefix}/chat/query/queryData`, chatContext);
|
return axios.post<MsgDataType>(`${prefix}/chat/query/queryData`, chatContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function queryContext(queryText: string, chatId?: number) {
|
export function queryContext(queryText: string, chatId?: number) {
|
||||||
return axios.post<Result<ChatContextType>>(`${prefix}/chat/query/queryContext`, {
|
return axios.post<ChatContextType>(`${prefix}/chat/query/queryContext`, {
|
||||||
queryText,
|
queryText,
|
||||||
chatId: chatId || DEFAULT_CHAT_ID,
|
chatId: chatId || DEFAULT_CHAT_ID,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHistoryMsg(current: number, chatId: number = DEFAULT_CHAT_ID, pageSize: number = 10) {
|
export function getHistoryMsg(current: number, chatId: number = DEFAULT_CHAT_ID, pageSize: number = 10) {
|
||||||
return axios.post<Result<HistoryType>>(`${prefix}/chat/manage/pageQueryInfo?chatId=${chatId}`, {
|
return axios.post<HistoryType>(`${prefix}/chat/manage/pageQueryInfo?chatId=${chatId}`, {
|
||||||
current,
|
current,
|
||||||
pageSize,
|
pageSize,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveConversation(chatName: string) {
|
export function saveConversation(chatName: string) {
|
||||||
return axios.post<Result<any>>(`${prefix}/chat/manage/save?chatName=${chatName}`);
|
return axios.post<any>(`${prefix}/chat/manage/save?chatName=${chatName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAllConversations() {
|
export function getAllConversations() {
|
||||||
return axios.get<Result<any>>(`${prefix}/chat/manage/getAll`);
|
return axios.get<any>(`${prefix}/chat/manage/getAll`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function queryEntities(entityId: string | number, modelId: number) {
|
export function queryEntities(entityId: string | number, modelId: number) {
|
||||||
return axios.post<Result<any>>(`${prefix}/chat/query/choice`, {
|
return axios.post<any>(`${prefix}/chat/query/choice`, {
|
||||||
entityId,
|
entityId,
|
||||||
modelId,
|
modelId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateQAFeedback(questionId: number, score: number) {
|
export function updateQAFeedback(questionId: number, score: number) {
|
||||||
return axios.post<Result<any>>(`${prefix}/chat/manage/updateQAFeedback?id=${questionId}&score=${score}&feedback=`);
|
return axios.post<any>(`${prefix}/chat/manage/updateQAFeedback?id=${questionId}&score=${score}&feedback=`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function queryDrillDownDimensions(modelId: number) {
|
export function queryDrillDownDimensions(modelId: number) {
|
||||||
return axios.get<Result<{ dimensions: DrillDownDimensionType[] }>>(`${prefix}/chat/recommend/metric/${modelId}`);
|
return axios.get<{ dimensions: DrillDownDimensionType[] }>(`${prefix}/chat/recommend/metric/${modelId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function queryDimensionValues(modelId: number, bizName: string, value: string) {
|
export function queryDimensionValues(modelId: number, bizName: string, value: string) {
|
||||||
return axios.post<Result<any>>(`${prefix}/chat/query/queryDimensionValue`, { modelId, bizName, value});
|
return axios.post<any>(`${prefix}/chat/query/queryDimensionValue`, { modelId, bizName, value});
|
||||||
}
|
}
|
||||||
|
|||||||
19
webapp/packages/chat-sdk/src/typings.d.ts
vendored
19
webapp/packages/chat-sdk/src/typings.d.ts
vendored
@@ -1,6 +1,7 @@
|
|||||||
declare module 'slash2';
|
declare module 'slash2';
|
||||||
declare module '*.css';
|
declare module '*.css';
|
||||||
declare module '*.less';
|
declare module '*.less';
|
||||||
|
declare module '*.module.less';
|
||||||
declare module '*.scss';
|
declare module '*.scss';
|
||||||
declare module '*.sass';
|
declare module '*.sass';
|
||||||
declare module '*.svg';
|
declare module '*.svg';
|
||||||
@@ -18,12 +19,22 @@ declare module 'react-fittext';
|
|||||||
declare module 'bizcharts-plugin-slider';
|
declare module 'bizcharts-plugin-slider';
|
||||||
declare module 'react-split-pane/lib/Pane';
|
declare module 'react-split-pane/lib/Pane';
|
||||||
|
|
||||||
// preview.pro.ant.design only do not use in your production ;
|
|
||||||
// preview.pro.ant.design Dedicated environment variable, please do not use it in your project.
|
|
||||||
declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined;
|
|
||||||
|
|
||||||
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
|
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
|
||||||
|
|
||||||
|
declare module '*.module.less' {
|
||||||
|
const classes: {
|
||||||
|
readonly [key: string]: string
|
||||||
|
}
|
||||||
|
export default classes
|
||||||
|
declare module '*.less'
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AxiosResponse<T = any> extends Promise<T> {
|
||||||
|
code: number;
|
||||||
|
data: T;
|
||||||
|
msg: string;
|
||||||
|
}
|
||||||
|
|
||||||
type Result<T> = {
|
type Result<T> = {
|
||||||
code: number;
|
code: number;
|
||||||
data: T;
|
data: T;
|
||||||
|
|||||||
@@ -178,9 +178,76 @@ export function isProd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setToken(token: string) {
|
export function setToken(token: string) {
|
||||||
localStorage.setItem('SUPERSONIC_CHAT_TOKEN', token);
|
localStorage.setItem('SUPERSONIC_TOKEN', token);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getToken() {
|
export function getToken() {
|
||||||
return localStorage.getItem('SUPERSONIC_CHAT_TOKEN');
|
return localStorage.getItem('SUPERSONIC_TOKEN');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const updateMessageContainerScroll = (nodeId?: string) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const ele: any = document.getElementById('messageContainer');
|
||||||
|
if (ele && ele.scrollHeight > ele.clientHeight) {
|
||||||
|
if (nodeId) {
|
||||||
|
const node = document.getElementById(nodeId);
|
||||||
|
if (node) {
|
||||||
|
ele.scrollTop = ele.scrollHeight - node.clientHeight - 130;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ele.scrollTop = ele.scrollHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UUID生成器
|
||||||
|
* @param len 长度 number
|
||||||
|
* @param radix 随机数基数 number
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export const uuid = (len: number = 8, radix: number = 62) => {
|
||||||
|
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
|
||||||
|
const uuid: string[] = [];
|
||||||
|
let i;
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
// Compact form
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
uuid[i] = chars[Math.floor(Math.random() * radix)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// rfc4122, version 4 form
|
||||||
|
let r;
|
||||||
|
|
||||||
|
// rfc4122 requires these characters
|
||||||
|
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
|
||||||
|
uuid[14] = '4';
|
||||||
|
|
||||||
|
// Fill in random data. At i==19 set the high bits of clock sequence as
|
||||||
|
// per rfc4122, sec. 4.1.5
|
||||||
|
for (i = 0; i < 36; i++) {
|
||||||
|
if (!uuid[i]) {
|
||||||
|
r = Math.floor(Math.random() * 16);
|
||||||
|
uuid[i] = chars[i === 19 ? ((r % 4) % 8) + 8 : r];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid.join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
let utilCanvas: any = null;
|
||||||
|
|
||||||
|
export const getTextWidth = (
|
||||||
|
text: string,
|
||||||
|
fontSize: string = '16px',
|
||||||
|
fontWeight: string = 'normal',
|
||||||
|
fontFamily: string = 'DINPro Medium',
|
||||||
|
): number => {
|
||||||
|
const canvas = utilCanvas || (utilCanvas = document.createElement('canvas'));
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
context.font = `${fontWeight} ${fontSize} ${fontFamily}`;
|
||||||
|
const metrics = context.measureText(text);
|
||||||
|
return Math.ceil(metrics.width);
|
||||||
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"moduleResolution":"Node",
|
"moduleResolution":"Node",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"importHelpers": true,
|
"importHelpers": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src"
|
"src"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const ENV_CONFIG = {
|
const ENV_CONFIG = {
|
||||||
tmeAvatarUrl: 'http://tpp.tmeoa.com/photo/48/',
|
tmeAvatarUrl: '',
|
||||||
};
|
};
|
||||||
export default ENV_CONFIG;
|
export default ENV_CONFIG;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const ROUTES = [
|
|||||||
{
|
{
|
||||||
path: '/chat/mobile',
|
path: '/chat/mobile',
|
||||||
name: 'chat',
|
name: 'chat',
|
||||||
component: './Chat',
|
component: './ChatPage',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
layout: false,
|
layout: false,
|
||||||
envEnableList: [ENV_KEY.CHAT],
|
envEnableList: [ENV_KEY.CHAT],
|
||||||
@@ -19,7 +19,7 @@ const ROUTES = [
|
|||||||
{
|
{
|
||||||
path: '/chat',
|
path: '/chat',
|
||||||
name: 'chat',
|
name: 'chat',
|
||||||
component: './Chat',
|
component: './ChatPage',
|
||||||
envEnableList: [ENV_KEY.CHAT],
|
envEnableList: [ENV_KEY.CHAT],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,23 +1,18 @@
|
|||||||
import { AUTH_TOKEN_KEY, FROM_URL_KEY } from '@/common/constants';
|
|
||||||
import RightContent from '@/components/RightContent';
|
import RightContent from '@/components/RightContent';
|
||||||
import S2Icon, { ICON } from '@/components/S2Icon';
|
import S2Icon, { ICON } from '@/components/S2Icon';
|
||||||
import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
|
import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
|
||||||
import { Space, Spin } from 'antd';
|
import { Space, Spin } from 'antd';
|
||||||
import qs from 'qs';
|
|
||||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||||
import type { RunTimeLayoutConfig } from 'umi';
|
import type { RunTimeLayoutConfig } from 'umi';
|
||||||
import { history } from 'umi';
|
import { history } from 'umi';
|
||||||
import defaultSettings from '../config/defaultSettings';
|
import defaultSettings from '../config/defaultSettings';
|
||||||
import settings from '../config/themeSettings';
|
import settings from '../config/themeSettings';
|
||||||
import { queryToken } from './services/login';
|
|
||||||
import { queryCurrentUser } from './services/user';
|
import { queryCurrentUser } from './services/user';
|
||||||
import { traverseRoutes, deleteUrlQuery, isMobile } from './utils/utils';
|
import { traverseRoutes, isMobile, getToken } from './utils/utils';
|
||||||
import { publicPath } from '../config/defaultSettings';
|
import { publicPath } from '../config/defaultSettings';
|
||||||
import Copilot from './pages/Copilot';
|
import { Copilot } from 'supersonic-chat-sdk';
|
||||||
export { request } from './services/request';
|
export { request } from './services/request';
|
||||||
|
|
||||||
const TOKEN_KEY = AUTH_TOKEN_KEY;
|
|
||||||
|
|
||||||
const replaceRoute = '/';
|
const replaceRoute = '/';
|
||||||
|
|
||||||
const getRunningEnv = async () => {
|
const getRunningEnv = async () => {
|
||||||
@@ -42,25 +37,6 @@ export const initialStateConfig = {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const getToken = async () => {
|
|
||||||
let { search } = window.location;
|
|
||||||
if (search.length > 0) {
|
|
||||||
search = search.slice(1);
|
|
||||||
}
|
|
||||||
const data = qs.parse(search);
|
|
||||||
if (data.code) {
|
|
||||||
try {
|
|
||||||
const fromUrl = localStorage.getItem(FROM_URL_KEY);
|
|
||||||
const res = await queryToken(data.code as string);
|
|
||||||
localStorage.setItem(TOKEN_KEY, res.payload);
|
|
||||||
const newUrl = deleteUrlQuery(window.location.href, 'code');
|
|
||||||
window.location.href = fromUrl || newUrl;
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAuthCodes = () => {
|
const getAuthCodes = () => {
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
@@ -81,12 +57,6 @@ export async function getInitialState(): Promise<{
|
|||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
const { query } = history.location as any;
|
|
||||||
const currentToken = query[TOKEN_KEY] || localStorage.getItem(TOKEN_KEY);
|
|
||||||
|
|
||||||
if (window.location.host.includes('tmeoa') && !currentToken) {
|
|
||||||
await getToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentUser: any;
|
let currentUser: any;
|
||||||
if (!window.location.pathname.includes('login')) {
|
if (!window.location.pathname.includes('login')) {
|
||||||
@@ -162,7 +132,9 @@ export const layout: RunTimeLayoutConfig = (params) => {
|
|||||||
style={{ height: location.pathname.includes('chat') ? 'calc(100vh - 48px)' : undefined }}
|
style={{ height: location.pathname.includes('chat') ? 'calc(100vh - 48px)' : undefined }}
|
||||||
>
|
>
|
||||||
{dom}
|
{dom}
|
||||||
{history.location.pathname !== '/chat' && !isMobile && <Copilot />}
|
{history.location.pathname !== '/chat' && !isMobile && (
|
||||||
|
<Copilot token={getToken() || ''} isDeveloper />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { CHAT_BLUE } from '@/common/constants';
|
|
||||||
import { Spin } from 'antd';
|
|
||||||
import BeatLoader from 'react-spinners/BeatLoader';
|
|
||||||
import Message from './Message';
|
|
||||||
import styles from './style.less';
|
|
||||||
|
|
||||||
const Typing = () => {
|
|
||||||
return (
|
|
||||||
<Message position="left" bubbleClassName={styles.typingBubble}>
|
|
||||||
<Spin
|
|
||||||
spinning={true}
|
|
||||||
indicator={<BeatLoader color={CHAT_BLUE} size={10} />}
|
|
||||||
className={styles.typing}
|
|
||||||
/>
|
|
||||||
</Message>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Typing;
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
import { isMobile } from '@/utils/utils';
|
|
||||||
import { request } from 'umi';
|
|
||||||
import { AgentType, ModelType } from './type';
|
|
||||||
|
|
||||||
const prefix = isMobile ? '/openapi' : '/api';
|
|
||||||
|
|
||||||
export function saveConversation(chatName: string, agentId: number) {
|
|
||||||
return request<Result<any>>(
|
|
||||||
`${prefix}/chat/manage/save?chatName=${chatName}&agentId=${agentId}`,
|
|
||||||
{
|
|
||||||
method: 'POST',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateConversationName(chatName: string, chatId: number = 0) {
|
|
||||||
return request<Result<any>>(
|
|
||||||
`${prefix}/chat/manage/updateChatName?chatName=${chatName}&chatId=${chatId}`,
|
|
||||||
{ method: 'POST' },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteConversation(chatId: number) {
|
|
||||||
return request<Result<any>>(`${prefix}/chat/manage/delete?chatId=${chatId}`, { method: 'POST' });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAllConversations(agentId?: number) {
|
|
||||||
return request<Result<any>>(`${prefix}/chat/manage/getAll`, { params: { agentId } });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMiniProgramList(entityId: string, modelId: number) {
|
|
||||||
return request<Result<any>>(
|
|
||||||
`${prefix}/chat/plugin/extend/getAvailablePlugin/${entityId}/${modelId}`,
|
|
||||||
{
|
|
||||||
method: 'GET',
|
|
||||||
skipErrorHandler: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getModelList() {
|
|
||||||
return request<Result<ModelType[]>>(`${prefix}/chat/conf/modelList/view`, {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateQAFeedback(questionId: number, score: number) {
|
|
||||||
return request<Result<any>>(
|
|
||||||
`${prefix}/chat/manage/updateQAFeedback?id=${questionId}&score=${score}&feedback=`,
|
|
||||||
{
|
|
||||||
method: 'POST',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function queryMetricSuggestion(modelId: number) {
|
|
||||||
return request<Result<any>>(`${prefix}/chat/recommend/metric/${modelId}`, {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function querySuggestion(modelId: number) {
|
|
||||||
return request<Result<any>>(`${prefix}/chat/recommend/${modelId}`, {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function queryRecommendQuestions() {
|
|
||||||
return request<Result<any>>(`${prefix}/chat/recommend/question`, {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function queryAgentList() {
|
|
||||||
return request<Result<AgentType[]>>(`${prefix}/chat/agent/getAgentList`, {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
14
webapp/packages/supersonic-fe/src/pages/ChatPage/index.tsx
Normal file
14
webapp/packages/supersonic-fe/src/pages/ChatPage/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { useLocation } from 'umi';
|
||||||
|
import { getToken } from '@/utils/utils';
|
||||||
|
import { Chat } from 'supersonic-chat-sdk';
|
||||||
|
|
||||||
|
const ChatPage = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
const { agentId } = (location as any).query;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Chat initialAgentId={agentId ? +agentId : undefined} token={getToken() || ''} isDeveloper />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChatPage;
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import IconFont from '@/components/IconFont';
|
|
||||||
import { CaretRightOutlined, CloseOutlined } from '@ant-design/icons';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import Chat from '../Chat';
|
|
||||||
import { DefaultEntityType, ModelType } from '../Chat/type';
|
|
||||||
import styles from './style.less';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
globalCopilotFilter: DefaultEntityType;
|
|
||||||
copilotSendMsg: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Copilot: React.FC<Props> = ({ globalCopilotFilter, copilotSendMsg }) => {
|
|
||||||
const [chatVisible, setChatVisible] = useState(false);
|
|
||||||
const [defaultModelName, setDefaultModelName] = useState('');
|
|
||||||
const [defaultEntityFilter, setDefaultEntityFilter] = useState<DefaultEntityType>();
|
|
||||||
const [triggerNewConversation, setTriggerNewConversation] = useState(false);
|
|
||||||
const [copilotMinimized, setCopilotMinimized] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (globalCopilotFilter && globalCopilotFilter.entityId !== defaultEntityFilter?.entityId) {
|
|
||||||
setTriggerNewConversation(true);
|
|
||||||
}
|
|
||||||
setDefaultEntityFilter(globalCopilotFilter);
|
|
||||||
if (globalCopilotFilter?.modelName) {
|
|
||||||
setDefaultModelName(globalCopilotFilter.modelName);
|
|
||||||
}
|
|
||||||
}, [globalCopilotFilter]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (copilotSendMsg) {
|
|
||||||
updateChatVisible(true);
|
|
||||||
setTriggerNewConversation(true);
|
|
||||||
}
|
|
||||||
}, [copilotSendMsg]);
|
|
||||||
|
|
||||||
const updateChatVisible = (visible: boolean) => {
|
|
||||||
setChatVisible(visible);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onToggleChatVisible = () => {
|
|
||||||
const chatVisibleValue = !chatVisible;
|
|
||||||
updateChatVisible(chatVisibleValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCloseChat = () => {
|
|
||||||
updateChatVisible(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTransferChat = () => {
|
|
||||||
window.open('/chat');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCurrentModelChange = (model?: ModelType) => {
|
|
||||||
setDefaultModelName(model?.name || '');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onNewConversationTriggered = () => {
|
|
||||||
setTriggerNewConversation(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMinimizeCopilot = (e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
updateChatVisible(false);
|
|
||||||
setCopilotMinimized(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const copilotClass = classNames(styles.copilot, {
|
|
||||||
[styles.copilotMinimized]: copilotMinimized,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
className={copilotClass}
|
|
||||||
onMouseEnter={() => {
|
|
||||||
setCopilotMinimized(false);
|
|
||||||
}}
|
|
||||||
onClick={onToggleChatVisible}
|
|
||||||
>
|
|
||||||
<IconFont type="icon-copilot-fill" />
|
|
||||||
<div className={styles.minimizeWrapper} onClick={onMinimizeCopilot}>
|
|
||||||
<div className={styles.minimize}>-</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={styles.copilotContent} style={{ display: chatVisible ? 'block' : 'none' }}>
|
|
||||||
<div className={styles.chatPopover}>
|
|
||||||
<div className={styles.header}>
|
|
||||||
<div className={styles.leftSection}>
|
|
||||||
<CloseOutlined className={styles.close} onClick={onCloseChat} />
|
|
||||||
<IconFont
|
|
||||||
type="icon-weibiaoti-"
|
|
||||||
className={styles.transfer}
|
|
||||||
onClick={onTransferChat}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.title}>Copilot</div>
|
|
||||||
</div>
|
|
||||||
<div className={styles.chat}>
|
|
||||||
<Chat
|
|
||||||
copilotSendMsg={copilotSendMsg}
|
|
||||||
defaultModelName={defaultModelName}
|
|
||||||
defaultEntityFilter={defaultEntityFilter}
|
|
||||||
triggerNewConversation={triggerNewConversation}
|
|
||||||
chatVisible={chatVisible}
|
|
||||||
isCopilotMode
|
|
||||||
onNewConversationTriggered={onNewConversationTriggered}
|
|
||||||
onCurrentModelChange={onCurrentModelChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<CaretRightOutlined className={styles.rightArrow} />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Copilot;
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import { request } from 'umi';
|
|
||||||
|
|
||||||
export type LoginParamsType = {
|
export type LoginParamsType = {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
@@ -7,9 +5,3 @@ export type LoginParamsType = {
|
|||||||
captcha: string;
|
captcha: string;
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function queryToken(code: string) {
|
|
||||||
return request(`/davinciapi/login/tmeloginCallback`, {
|
|
||||||
params: { code },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
191
webapp/pnpm-lock.yaml
generated
191
webapp/pnpm-lock.yaml
generated
@@ -14,12 +14,15 @@ importers:
|
|||||||
'@uiw/react-watermark':
|
'@uiw/react-watermark':
|
||||||
specifier: ^0.0.5
|
specifier: ^0.0.5
|
||||||
version: 0.0.5(react-dom@18.2.0)(react@18.2.0)
|
version: 0.0.5(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
ahooks:
|
||||||
|
specifier: ^3.7.8
|
||||||
|
version: 3.7.8(react@18.2.0)
|
||||||
antd:
|
antd:
|
||||||
specifier: ^5.5.2
|
specifier: ^5.5.2
|
||||||
version: 5.9.0(moment@2.29.4)(react-dom@18.2.0)(react@18.2.0)
|
version: 5.9.0(moment@2.29.4)(react-dom@18.2.0)(react@18.2.0)
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.4.0
|
specifier: ^0.21.1
|
||||||
version: 1.4.0
|
version: 0.21.4
|
||||||
classnames:
|
classnames:
|
||||||
specifier: ^2.3.2
|
specifier: ^2.3.2
|
||||||
version: 2.3.2
|
version: 2.3.2
|
||||||
@@ -32,9 +35,18 @@ importers:
|
|||||||
moment:
|
moment:
|
||||||
specifier: ^2.29.4
|
specifier: ^2.29.4
|
||||||
version: 2.29.4
|
version: 2.29.4
|
||||||
|
react-copy-to-clipboard:
|
||||||
|
specifier: ^5.1.0
|
||||||
|
version: 5.1.0(react@18.2.0)
|
||||||
react-spinners:
|
react-spinners:
|
||||||
specifier: ^0.13.8
|
specifier: ^0.13.8
|
||||||
version: 0.13.8(react-dom@18.2.0)(react@18.2.0)
|
version: 0.13.8(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
react-syntax-highlighter:
|
||||||
|
specifier: ^15.5.0
|
||||||
|
version: 15.5.0(react@18.2.0)
|
||||||
|
sql-formatter:
|
||||||
|
specifier: ^2.3.3
|
||||||
|
version: 2.3.4
|
||||||
tslib:
|
tslib:
|
||||||
specifier: ^2.5.2
|
specifier: ^2.5.2
|
||||||
version: 2.6.2
|
version: 2.6.2
|
||||||
@@ -75,6 +87,9 @@ importers:
|
|||||||
'@types/jest':
|
'@types/jest':
|
||||||
specifier: ^27.5.2
|
specifier: ^27.5.2
|
||||||
version: 27.5.2
|
version: 27.5.2
|
||||||
|
'@types/lodash':
|
||||||
|
specifier: ^4.14.198
|
||||||
|
version: 4.14.198
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^16.18.31
|
specifier: ^16.18.31
|
||||||
version: 16.18.50
|
version: 16.18.50
|
||||||
@@ -225,6 +240,9 @@ importers:
|
|||||||
rollup-plugin-postcss:
|
rollup-plugin-postcss:
|
||||||
specifier: ^4.0.2
|
specifier: ^4.0.2
|
||||||
version: 4.0.2(postcss@8.4.29)
|
version: 4.0.2(postcss@8.4.29)
|
||||||
|
rollup-plugin-styles:
|
||||||
|
specifier: ^4.0.0
|
||||||
|
version: 4.0.0(rollup@3.29.1)
|
||||||
rollup-plugin-typescript2:
|
rollup-plugin-typescript2:
|
||||||
specifier: ^0.34.1
|
specifier: ^0.34.1
|
||||||
version: 0.34.1(rollup@3.29.1)(typescript@4.9.5)
|
version: 0.34.1(rollup@3.29.1)(typescript@4.9.5)
|
||||||
@@ -5502,6 +5520,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-t33RNmTu5ufG/sorROIafiCVJMx3jz95bXUMoPAZcUD14fxMXnuTzqzXZoxpR0tNx2xpw11Dlmem9vGCsrSOfA==}
|
resolution: {integrity: sha512-t33RNmTu5ufG/sorROIafiCVJMx3jz95bXUMoPAZcUD14fxMXnuTzqzXZoxpR0tNx2xpw11Dlmem9vGCsrSOfA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/cssnano@5.1.0(postcss@8.4.29):
|
||||||
|
resolution: {integrity: sha512-ikR+18UpFGgvaWSur4og6SJYF/6QEYHXvrIt36dp81p1MG3cAPTYDMBJGeyWa3LCnqEbgNMHKRb+FP0NrXtoWQ==}
|
||||||
|
deprecated: This is a stub types definition. cssnano provides its own type definitions, so you do not need this installed.
|
||||||
|
dependencies:
|
||||||
|
cssnano: 6.0.1(postcss@8.4.29)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- postcss
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/d3-timer@2.0.1:
|
/@types/d3-timer@2.0.1:
|
||||||
resolution: {integrity: sha512-TF8aoF5cHcLO7W7403blM7L1T+6NF3XMyN3fxyUolq2uOcFeicG/khQg/dGxiCJWoAcmYulYN7LYSRKO54IXaA==}
|
resolution: {integrity: sha512-TF8aoF5cHcLO7W7403blM7L1T+6NF3XMyN3fxyUolq2uOcFeicG/khQg/dGxiCJWoAcmYulYN7LYSRKO54IXaA==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -7329,6 +7356,25 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ahooks@3.7.8(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-e/NMlQWoCjaUtncNFIZk3FG1ImSkV/JhScQSkTqnftakRwdfZWSw6zzoWSG9OMYqPNs2MguDYBUFFC6THelWXA==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.15
|
||||||
|
'@types/js-cookie': 2.2.7
|
||||||
|
ahooks-v3-count: 1.0.0
|
||||||
|
dayjs: 1.11.9
|
||||||
|
intersection-observer: 0.12.2
|
||||||
|
js-cookie: 2.2.1
|
||||||
|
lodash: 4.17.21
|
||||||
|
react: 18.2.0
|
||||||
|
resize-observer-polyfill: 1.5.1
|
||||||
|
screenfull: 5.2.0
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ajv-errors@1.0.1(ajv@6.12.6):
|
/ajv-errors@1.0.1(ajv@6.12.6):
|
||||||
resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==}
|
resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -7887,6 +7933,7 @@ packages:
|
|||||||
|
|
||||||
/asynckit@0.4.0:
|
/asynckit@0.4.0:
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/at-least-node@1.0.0:
|
/at-least-node@1.0.0:
|
||||||
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
||||||
@@ -7953,12 +8000,10 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/axios@1.4.0:
|
/axios@0.21.4:
|
||||||
resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
|
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.2
|
follow-redirects: 1.15.2
|
||||||
form-data: 4.0.0
|
|
||||||
proxy-from-env: 1.1.0
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
dev: false
|
dev: false
|
||||||
@@ -9146,6 +9191,7 @@ packages:
|
|||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/comma-separated-tokens@1.0.8:
|
/comma-separated-tokens@1.0.8:
|
||||||
resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==}
|
resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==}
|
||||||
@@ -9555,7 +9601,7 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/css-blank-pseudo@3.0.3(postcss@8.4.29):
|
/css-blank-pseudo@3.0.3(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==}
|
resolution: {integrity: sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==}
|
||||||
@@ -9587,7 +9633,7 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-selector-parser: 5.0.0
|
postcss-selector-parser: 5.0.0
|
||||||
|
|
||||||
/css-has-pseudo@3.0.4(postcss@8.4.29):
|
/css-has-pseudo@3.0.4(postcss@8.4.29):
|
||||||
@@ -9664,7 +9710,7 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/css-prefers-color-scheme@6.0.3(postcss@8.4.29):
|
/css-prefers-color-scheme@6.0.3(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==}
|
resolution: {integrity: sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==}
|
||||||
@@ -10312,6 +10358,7 @@ packages:
|
|||||||
/delayed-stream@1.0.0:
|
/delayed-stream@1.0.0:
|
||||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/depd@1.1.2:
|
/depd@1.1.2:
|
||||||
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
|
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
|
||||||
@@ -12452,6 +12499,7 @@ packages:
|
|||||||
asynckit: 0.4.0
|
asynckit: 0.4.0
|
||||||
combined-stream: 1.0.8
|
combined-stream: 1.0.8
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
|
dev: true
|
||||||
|
|
||||||
/format@0.2.2:
|
/format@0.2.2:
|
||||||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||||
@@ -17920,7 +17968,7 @@ packages:
|
|||||||
/postcss-attribute-case-insensitive@4.0.2:
|
/postcss-attribute-case-insensitive@4.0.2:
|
||||||
resolution: {integrity: sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==}
|
resolution: {integrity: sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-selector-parser: 6.0.13
|
postcss-selector-parser: 6.0.13
|
||||||
|
|
||||||
/postcss-attribute-case-insensitive@5.0.2(postcss@8.4.29):
|
/postcss-attribute-case-insensitive@5.0.2(postcss@8.4.29):
|
||||||
@@ -17979,7 +18027,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==}
|
resolution: {integrity: sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-color-functional-notation@4.2.4(postcss@8.4.29):
|
/postcss-color-functional-notation@4.2.4(postcss@8.4.29):
|
||||||
@@ -17997,14 +18045,14 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/convert-colors': 1.4.0
|
'@csstools/convert-colors': 1.4.0
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-color-hex-alpha@5.0.3:
|
/postcss-color-hex-alpha@5.0.3:
|
||||||
resolution: {integrity: sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==}
|
resolution: {integrity: sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-color-hex-alpha@8.0.4(postcss@8.4.29):
|
/postcss-color-hex-alpha@8.0.4(postcss@8.4.29):
|
||||||
@@ -18022,14 +18070,14 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/convert-colors': 1.4.0
|
'@csstools/convert-colors': 1.4.0
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-color-rebeccapurple@4.0.1:
|
/postcss-color-rebeccapurple@4.0.1:
|
||||||
resolution: {integrity: sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==}
|
resolution: {integrity: sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-color-rebeccapurple@7.1.1(postcss@8.4.29):
|
/postcss-color-rebeccapurple@7.1.1(postcss@8.4.29):
|
||||||
@@ -18094,7 +18142,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==}
|
resolution: {integrity: sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-custom-media@8.0.2(postcss@8.4.29):
|
/postcss-custom-media@8.0.2(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==}
|
resolution: {integrity: sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==}
|
||||||
@@ -18120,14 +18168,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==}
|
resolution: {integrity: sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-custom-selectors@5.1.2:
|
/postcss-custom-selectors@5.1.2:
|
||||||
resolution: {integrity: sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==}
|
resolution: {integrity: sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-selector-parser: 5.0.0
|
postcss-selector-parser: 5.0.0
|
||||||
|
|
||||||
/postcss-custom-selectors@6.0.3(postcss@8.4.29):
|
/postcss-custom-selectors@6.0.3(postcss@8.4.29):
|
||||||
@@ -18144,7 +18192,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==}
|
resolution: {integrity: sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==}
|
||||||
engines: {node: '>=4.0.0'}
|
engines: {node: '>=4.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-selector-parser: 5.0.0
|
postcss-selector-parser: 5.0.0
|
||||||
|
|
||||||
/postcss-dir-pseudo-class@6.0.5(postcss@8.4.29):
|
/postcss-dir-pseudo-class@6.0.5(postcss@8.4.29):
|
||||||
@@ -18233,7 +18281,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==}
|
resolution: {integrity: sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-double-position-gradients@3.1.2(postcss@8.4.29):
|
/postcss-double-position-gradients@3.1.2(postcss@8.4.29):
|
||||||
@@ -18251,7 +18299,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==}
|
resolution: {integrity: sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-env-function@4.0.6(postcss@8.4.29):
|
/postcss-env-function@4.0.6(postcss@8.4.29):
|
||||||
@@ -18267,7 +18315,7 @@ packages:
|
|||||||
/postcss-flexbugs-fixes@4.2.1:
|
/postcss-flexbugs-fixes@4.2.1:
|
||||||
resolution: {integrity: sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==}
|
resolution: {integrity: sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-flexbugs-fixes@5.0.2(postcss@8.4.29):
|
/postcss-flexbugs-fixes@5.0.2(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==}
|
resolution: {integrity: sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==}
|
||||||
@@ -18281,7 +18329,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==}
|
resolution: {integrity: sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-focus-visible@6.0.4(postcss@8.4.29):
|
/postcss-focus-visible@6.0.4(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==}
|
resolution: {integrity: sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==}
|
||||||
@@ -18297,7 +18345,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==}
|
resolution: {integrity: sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-focus-within@5.0.4(postcss@8.4.29):
|
/postcss-focus-within@5.0.4(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==}
|
resolution: {integrity: sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==}
|
||||||
@@ -18312,7 +18360,7 @@ packages:
|
|||||||
/postcss-font-variant@4.0.1:
|
/postcss-font-variant@4.0.1:
|
||||||
resolution: {integrity: sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==}
|
resolution: {integrity: sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-font-variant@5.0.0(postcss@8.4.29):
|
/postcss-font-variant@5.0.0(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==}
|
resolution: {integrity: sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==}
|
||||||
@@ -18326,7 +18374,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==}
|
resolution: {integrity: sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-gap-properties@3.0.5(postcss@8.4.29):
|
/postcss-gap-properties@3.0.5(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==}
|
resolution: {integrity: sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==}
|
||||||
@@ -18352,7 +18400,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==}
|
resolution: {integrity: sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-image-set-function@4.0.7(postcss@8.4.29):
|
/postcss-image-set-function@4.0.7(postcss@8.4.29):
|
||||||
@@ -18380,7 +18428,7 @@ packages:
|
|||||||
/postcss-initial@3.0.4:
|
/postcss-initial@3.0.4:
|
||||||
resolution: {integrity: sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==}
|
resolution: {integrity: sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-initial@4.0.1(postcss@8.4.29):
|
/postcss-initial@4.0.1(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==}
|
resolution: {integrity: sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==}
|
||||||
@@ -18412,7 +18460,7 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/convert-colors': 1.4.0
|
'@csstools/convert-colors': 1.4.0
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-lab-function@4.2.1(postcss@8.4.29):
|
/postcss-lab-function@4.2.1(postcss@8.4.29):
|
||||||
@@ -18486,7 +18534,7 @@ packages:
|
|||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
loader-utils: 1.4.2
|
loader-utils: 1.4.2
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-load-config: 2.1.2
|
postcss-load-config: 2.1.2
|
||||||
schema-utils: 1.0.0
|
schema-utils: 1.0.0
|
||||||
|
|
||||||
@@ -18508,7 +18556,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==}
|
resolution: {integrity: sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-logical@5.0.4(postcss@8.4.29):
|
/postcss-logical@5.0.4(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==}
|
resolution: {integrity: sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==}
|
||||||
@@ -18523,7 +18571,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==}
|
resolution: {integrity: sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-media-minmax@5.0.0(postcss@8.4.29):
|
/postcss-media-minmax@5.0.0(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==}
|
resolution: {integrity: sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==}
|
||||||
@@ -18772,7 +18820,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==}
|
resolution: {integrity: sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-normalize-charset@5.1.0(postcss@8.4.29):
|
/postcss-normalize-charset@5.1.0(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==}
|
resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==}
|
||||||
@@ -19004,7 +19052,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==}
|
resolution: {integrity: sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-overflow-shorthand@3.0.4(postcss@8.4.29):
|
/postcss-overflow-shorthand@3.0.4(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==}
|
resolution: {integrity: sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==}
|
||||||
@@ -19019,7 +19067,7 @@ packages:
|
|||||||
/postcss-page-break@2.0.0:
|
/postcss-page-break@2.0.0:
|
||||||
resolution: {integrity: sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==}
|
resolution: {integrity: sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-page-break@3.0.4(postcss@8.4.29):
|
/postcss-page-break@3.0.4(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==}
|
resolution: {integrity: sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==}
|
||||||
@@ -19033,7 +19081,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==}
|
resolution: {integrity: sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-values-parser: 2.0.1
|
postcss-values-parser: 2.0.1
|
||||||
|
|
||||||
/postcss-place@7.0.5(postcss@8.4.29):
|
/postcss-place@7.0.5(postcss@8.4.29):
|
||||||
@@ -19057,7 +19105,7 @@ packages:
|
|||||||
css-has-pseudo: 0.10.0
|
css-has-pseudo: 0.10.0
|
||||||
css-prefers-color-scheme: 3.1.1
|
css-prefers-color-scheme: 3.1.1
|
||||||
cssdb: 4.4.0
|
cssdb: 4.4.0
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-attribute-case-insensitive: 4.0.2
|
postcss-attribute-case-insensitive: 4.0.2
|
||||||
postcss-color-functional-notation: 2.0.1
|
postcss-color-functional-notation: 2.0.1
|
||||||
postcss-color-gray: 5.0.0
|
postcss-color-gray: 5.0.0
|
||||||
@@ -19150,7 +19198,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==}
|
resolution: {integrity: sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
postcss-selector-parser: 5.0.0
|
postcss-selector-parser: 5.0.0
|
||||||
|
|
||||||
/postcss-pseudo-class-any-link@7.1.6(postcss@8.4.29):
|
/postcss-pseudo-class-any-link@7.1.6(postcss@8.4.29):
|
||||||
@@ -19208,7 +19256,7 @@ packages:
|
|||||||
/postcss-replace-overflow-wrap@3.0.0:
|
/postcss-replace-overflow-wrap@3.0.0:
|
||||||
resolution: {integrity: sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==}
|
resolution: {integrity: sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-replace-overflow-wrap@4.0.0(postcss@8.4.29):
|
/postcss-replace-overflow-wrap@4.0.0(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==}
|
resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==}
|
||||||
@@ -19246,13 +19294,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==}
|
resolution: {integrity: sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==}
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-selector-not@4.0.1:
|
/postcss-selector-not@4.0.1:
|
||||||
resolution: {integrity: sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==}
|
resolution: {integrity: sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
postcss: 7.0.32
|
postcss: 7.0.39
|
||||||
|
|
||||||
/postcss-selector-not@6.0.1(postcss@8.4.29):
|
/postcss-selector-not@6.0.1(postcss@8.4.29):
|
||||||
resolution: {integrity: sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==}
|
resolution: {integrity: sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==}
|
||||||
@@ -19644,6 +19692,7 @@ packages:
|
|||||||
|
|
||||||
/proxy-from-env@1.1.0:
|
/proxy-from-env@1.1.0:
|
||||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/prr@1.0.1:
|
/prr@1.0.1:
|
||||||
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
|
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
|
||||||
@@ -19792,6 +19841,16 @@ packages:
|
|||||||
split-on-first: 1.1.0
|
split-on-first: 1.1.0
|
||||||
strict-uri-encode: 2.0.0
|
strict-uri-encode: 2.0.0
|
||||||
|
|
||||||
|
/query-string@7.1.3:
|
||||||
|
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dependencies:
|
||||||
|
decode-uri-component: 0.2.2
|
||||||
|
filter-obj: 1.1.0
|
||||||
|
split-on-first: 1.1.0
|
||||||
|
strict-uri-encode: 2.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/querystring-es3@0.2.1:
|
/querystring-es3@0.2.1:
|
||||||
resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==}
|
resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==}
|
||||||
engines: {node: '>=0.4.x'}
|
engines: {node: '>=0.4.x'}
|
||||||
@@ -21140,6 +21199,16 @@ packages:
|
|||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-copy-to-clipboard@5.1.0(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^15.3.0 || 16 || 17 || 18
|
||||||
|
dependencies:
|
||||||
|
copy-to-clipboard: 3.3.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-dev-inspector@1.9.0(eslint@7.32.0)(react@17.0.2)(typescript@4.9.5)(webpack@5.88.2):
|
/react-dev-inspector@1.9.0(eslint@7.32.0)(react@17.0.2)(typescript@4.9.5)(webpack@5.88.2):
|
||||||
resolution: {integrity: sha512-1ZlraWRrDz+NgjHwOmTAn/wWoP+6gZt46DS1mRRILlST0iKg4FO2Zj9dDcG5XPaeIIr3OGKwsX5vM6vakmaftA==}
|
resolution: {integrity: sha512-1ZlraWRrDz+NgjHwOmTAn/wWoP+6gZt46DS1mRRILlST0iKg4FO2Zj9dDcG5XPaeIIr3OGKwsX5vM6vakmaftA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -21623,6 +21692,19 @@ packages:
|
|||||||
refractor: 3.6.0
|
refractor: 3.6.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-syntax-highlighter@15.5.0(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>= 0.14.0'
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.15
|
||||||
|
highlight.js: 10.7.3
|
||||||
|
lowlight: 1.20.0
|
||||||
|
prismjs: 1.29.0
|
||||||
|
react: 18.2.0
|
||||||
|
refractor: 3.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-tween-state@0.1.5:
|
/react-tween-state@0.1.5:
|
||||||
resolution: {integrity: sha512-sJQpjsdn0wjlDIUpfpb7jQGnOG8hAEW2e8k0KPA+xmf5KFa6Xat2JldbmxBhaqP0S/uIXhVE5ymKyH/b9X8nYA==}
|
resolution: {integrity: sha512-sJQpjsdn0wjlDIUpfpb7jQGnOG8hAEW2e8k0KPA+xmf5KFa6Xat2JldbmxBhaqP0S/uIXhVE5ymKyH/b9X8nYA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -22478,6 +22560,33 @@ packages:
|
|||||||
- ts-node
|
- ts-node
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/rollup-plugin-styles@4.0.0(rollup@3.29.1):
|
||||||
|
resolution: {integrity: sha512-A2K2sao84OsTmDxXG83JTCdXWrmgvQkkI38XDat46rdtpGMRm9tSYqeCdlwwGDJF4kKIafhV1mUidqu8MxUGig==}
|
||||||
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^2.63.0
|
||||||
|
dependencies:
|
||||||
|
'@rollup/pluginutils': 4.2.1
|
||||||
|
'@types/cssnano': 5.1.0(postcss@8.4.29)
|
||||||
|
cosmiconfig: 7.1.0
|
||||||
|
cssnano: 5.1.15(postcss@8.4.29)
|
||||||
|
fs-extra: 10.1.0
|
||||||
|
icss-utils: 5.1.0(postcss@8.4.29)
|
||||||
|
mime-types: 2.1.35
|
||||||
|
p-queue: 6.6.2
|
||||||
|
postcss: 8.4.29
|
||||||
|
postcss-modules-extract-imports: 3.0.0(postcss@8.4.29)
|
||||||
|
postcss-modules-local-by-default: 4.0.3(postcss@8.4.29)
|
||||||
|
postcss-modules-scope: 3.0.0(postcss@8.4.29)
|
||||||
|
postcss-modules-values: 4.0.0(postcss@8.4.29)
|
||||||
|
postcss-value-parser: 4.2.0
|
||||||
|
query-string: 7.1.3
|
||||||
|
resolve: 1.22.4
|
||||||
|
rollup: 3.29.1
|
||||||
|
source-map-js: 1.0.2
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/rollup-plugin-terser@7.0.2(rollup@2.79.1):
|
/rollup-plugin-terser@7.0.2(rollup@2.79.1):
|
||||||
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
|
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
|
||||||
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
|
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
|
||||||
|
|||||||
Reference in New Issue
Block a user