mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 20:37:48 +00:00
Perf workflow (#1492)
* perf: handle edge check * search model * feat: plugin input can render all input; fix: plugin default value * fix ts * feat: plugin input support required
This commit is contained in:
1
.vscode/i18n-ally-custom-framework.yml
vendored
1
.vscode/i18n-ally-custom-framework.yml
vendored
@@ -23,6 +23,7 @@ usageMatchRegex:
|
|||||||
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
|
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
|
||||||
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
|
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
|
||||||
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
|
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
|
||||||
|
- "[^\\w\\d]workflowT\\(['\"`]({key})['\"`]"
|
||||||
|
|
||||||
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
|
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
|
||||||
# and works like how the i18next framework identifies the namespace scope from the
|
# and works like how the i18next framework identifies the namespace scope from the
|
||||||
|
@@ -247,7 +247,7 @@ curl --location --request POST '{{host}}/shareAuth/finish' \
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
type ResponseType = {
|
type ResponseType = {
|
||||||
moduleType: `${FlowNodeTypeEnum}`; // 模块类型
|
moduleType: FlowNodeTypeEnum; // 模块类型
|
||||||
moduleName: string; // 模块名
|
moduleName: string; // 模块名
|
||||||
moduleLogo?: string; // logo
|
moduleLogo?: string; // logo
|
||||||
runningTime?: number; // 运行时间
|
runningTime?: number; // 运行时间
|
||||||
|
@@ -35,5 +35,8 @@ curl --location --request POST 'https://{{host}}/api/admin/clearInvalidData' \
|
|||||||
## V4.8.1 更新说明
|
## V4.8.1 更新说明
|
||||||
|
|
||||||
1. 新增 - 知识库重新选择向量模型重建
|
1. 新增 - 知识库重新选择向量模型重建
|
||||||
2. 修复 - 工作流删除节点的动态输入和输出时候,没有正确的删除连接线,导致可能出现逻辑异常。
|
2. 新增 - 工作流节点版本变更提示,并可以同步最新版本。
|
||||||
3. 修复 - 定时器清理脏数据任务
|
3. 优化 - 插件输入的 debug 模式,支持全量参数输入渲染。
|
||||||
|
4. 修复 - 插件输入默认值被清空问题。
|
||||||
|
5. 修复 - 工作流删除节点的动态输入和输出时候,没有正确的删除连接线,导致可能出现逻辑异常。
|
||||||
|
6. 修复 - 定时器清理脏数据任务
|
2
packages/global/core/chat/type.d.ts
vendored
2
packages/global/core/chat/type.d.ts
vendored
@@ -139,7 +139,7 @@ export type ChatHistoryItemType = HistoryItemType & {
|
|||||||
/* ------- response data ------------ */
|
/* ------- response data ------------ */
|
||||||
export type ChatHistoryItemResType = DispatchNodeResponseType & {
|
export type ChatHistoryItemResType = DispatchNodeResponseType & {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
moduleType: `${FlowNodeTypeEnum}`;
|
moduleType: FlowNodeTypeEnum;
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
packages/global/core/workflow/api.d.ts
vendored
2
packages/global/core/workflow/api.d.ts
vendored
@@ -1,7 +1,7 @@
|
|||||||
import { VectorModelItemType } from '../ai/model.d';
|
import { VectorModelItemType } from '../ai/model.d';
|
||||||
import { NodeInputKeyEnum } from './constants';
|
import { NodeInputKeyEnum } from './constants';
|
||||||
|
|
||||||
export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[];
|
export type SelectedDatasetType = { datasetId: string }[];
|
||||||
|
|
||||||
export type HttpBodyType<T = Record<string, any>> = {
|
export type HttpBodyType<T = Record<string, any>> = {
|
||||||
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
|
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
|
||||||
|
@@ -36,7 +36,6 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
|
|||||||
label: 'core.module.input.label.Select dataset',
|
label: 'core.module.input.label.Select dataset',
|
||||||
value: [],
|
value: [],
|
||||||
valueType: WorkflowIOValueTypeEnum.selectDataset,
|
valueType: WorkflowIOValueTypeEnum.selectDataset,
|
||||||
list: [],
|
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -22,7 +22,7 @@ import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge';
|
|||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
|
|
||||||
export type FlowNodeCommonType = {
|
export type FlowNodeCommonType = {
|
||||||
flowNodeType: `${FlowNodeTypeEnum}`; // render node card
|
flowNodeType: FlowNodeTypeEnum; // render node card
|
||||||
|
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './node/constant';
|
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './node/constant';
|
||||||
import {
|
import {
|
||||||
WorkflowIOValueTypeEnum,
|
WorkflowIOValueTypeEnum,
|
||||||
NodeInputKeyEnum,
|
NodeInputKeyEnum,
|
||||||
@@ -22,15 +22,9 @@ export const getHandleId = (nodeId: string, type: 'source' | 'target', key: stri
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const checkInputIsReference = (input: FlowNodeInputItemType) => {
|
export const checkInputIsReference = (input: FlowNodeInputItemType) => {
|
||||||
const value = input.value;
|
if (input.renderTypeList?.[input?.selectedTypeIndex || 0] === FlowNodeInputTypeEnum.reference)
|
||||||
if (
|
|
||||||
Array.isArray(value) &&
|
|
||||||
value.length === 2 &&
|
|
||||||
typeof value[0] === 'string' &&
|
|
||||||
typeof value[1] === 'string'
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -15,6 +15,7 @@ import { getHistories } from '../utils';
|
|||||||
import { datasetSearchQueryExtension } from '../../../dataset/search/utils';
|
import { datasetSearchQueryExtension } from '../../../dataset/search/utils';
|
||||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit';
|
import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit';
|
||||||
|
import { MongoDataset } from '../../../dataset/schema';
|
||||||
|
|
||||||
type DatasetSearchProps = ModuleDispatchProps<{
|
type DatasetSearchProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
[NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
||||||
@@ -79,7 +80,9 @@ export async function dispatchDatasetSearch(
|
|||||||
// console.log(concatQueries, rewriteQuery, aiExtensionResult);
|
// console.log(concatQueries, rewriteQuery, aiExtensionResult);
|
||||||
|
|
||||||
// get vector
|
// get vector
|
||||||
const vectorModel = getVectorModel(datasets[0]?.vectorModel?.model);
|
const vectorModel = getVectorModel(
|
||||||
|
(await MongoDataset.findById(datasets[0].datasetId, 'vectorModel').lean())?.vectorModel
|
||||||
|
);
|
||||||
|
|
||||||
// start search
|
// start search
|
||||||
const {
|
const {
|
||||||
|
@@ -45,7 +45,7 @@ import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime
|
|||||||
import { dispatchSystemConfig } from './init/systemConfig';
|
import { dispatchSystemConfig } from './init/systemConfig';
|
||||||
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
||||||
|
|
||||||
const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
|
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||||
[FlowNodeTypeEnum.answerNode]: dispatchAnswer,
|
[FlowNodeTypeEnum.answerNode]: dispatchAnswer,
|
||||||
[FlowNodeTypeEnum.chatNode]: dispatchChatCompletion,
|
[FlowNodeTypeEnum.chatNode]: dispatchChatCompletion,
|
||||||
|
36
packages/web/components/common/Input/NumberInput/index.tsx
Normal file
36
packages/web/components/common/Input/NumberInput/index.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import {
|
||||||
|
NumberInput,
|
||||||
|
NumberIncrementStepper,
|
||||||
|
NumberInputField,
|
||||||
|
NumberInputStepper,
|
||||||
|
NumberDecrementStepper,
|
||||||
|
NumberInputProps
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = Omit<NumberInputProps, 'onChange'> & {
|
||||||
|
onChange: (e: number | '') => any;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyNumberInput = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<NumberInput
|
||||||
|
{...props}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (isNaN(Number(e))) {
|
||||||
|
props?.onChange('');
|
||||||
|
} else {
|
||||||
|
props?.onChange(Number(e));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
<NumberInputStepper>
|
||||||
|
<NumberIncrementStepper />
|
||||||
|
<NumberDecrementStepper />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MyNumberInput;
|
@@ -67,7 +67,7 @@ const MyRightDrawer = ({
|
|||||||
<DrawerCloseButton position={'relative'} fontSize={'sm'} top={0} right={0} />
|
<DrawerCloseButton position={'relative'} fontSize={'sm'} top={0} right={0} />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<DrawerBody>
|
<DrawerBody overflow={'unset'} px={props?.px}>
|
||||||
{children}
|
{children}
|
||||||
<Loading loading={isLoading} fixed={false} />
|
<Loading loading={isLoading} fixed={false} />
|
||||||
</DrawerBody>
|
</DrawerBody>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Common Dataset": "Common dataset",
|
"Common Dataset": "Common dataset",
|
||||||
"Common Dataset Desc": "Can be built by importing files, web links, or manual entry",
|
"Common Dataset Desc": "Can be built by importing files, web links, or manual entry",
|
||||||
"Confirm to rebuild embedding tip": "Are you sure to switch the knowledge base index? Switching index is a very heavy operation that requires re-indexing all the data in your knowledge base, which may take a long time. Please ensure that the remaining points in your account are sufficient.",
|
"Confirm to rebuild embedding tip": "Are you sure to switch the knowledge base index?\nSwitching index is a very heavy operation that requires re-indexing all the data in your knowledge base, which may take a long time. Please ensure that the remaining points in your account are sufficient.\n\nIn addition, you need to be careful to modify the applications that select this knowledge base to avoid mixing them with other index model knowledge bases.",
|
||||||
"External file": "External file",
|
"External file": "External file",
|
||||||
"External file Dataset Desc": "You can import files from an external file library to build a knowledge base. Files are not stored twice",
|
"External file Dataset Desc": "You can import files from an external file library to build a knowledge base. Files are not stored twice",
|
||||||
"External id": "File id",
|
"External id": "File id",
|
||||||
|
3
projects/app/i18n/en/workflow.json
Normal file
3
projects/app/i18n/en/workflow.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"Field required": "Required"
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Common Dataset": "通用知识库",
|
"Common Dataset": "通用知识库",
|
||||||
"Common Dataset Desc": "可通过导入文件、网页链接或手动录入形式构建知识库",
|
"Common Dataset Desc": "可通过导入文件、网页链接或手动录入形式构建知识库",
|
||||||
"Confirm to rebuild embedding tip": "确认为知识库切换索引?\n切换索引是一个非常重量的操作,需要对您知识库内所有数据进行重新索引,时间可能较长,请确保账号内剩余积分充足。",
|
"Confirm to rebuild embedding tip": "确认为知识库切换索引?\n切换索引是一个非常重量的操作,需要对您知识库内所有数据进行重新索引,时间可能较长,请确保账号内剩余积分充足。\n\n此外,你还需要注意修改选择该知识库的应用,避免它们与其他索引模型知识库混用。",
|
||||||
"External File": "外部文件库",
|
"External File": "外部文件库",
|
||||||
"External file Dataset Desc": "可以从外部文件库导入文件构建知识库,文件不会进行二次存储",
|
"External file Dataset Desc": "可以从外部文件库导入文件构建知识库,文件不会进行二次存储",
|
||||||
"External id": "文件阅读ID",
|
"External id": "文件阅读ID",
|
||||||
|
3
projects/app/i18n/zh/workflow.json
Normal file
3
projects/app/i18n/zh/workflow.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"Field required": "必填"
|
||||||
|
}
|
@@ -96,7 +96,7 @@ export const DatasetSelectModal = ({
|
|||||||
_hover={{ color: 'red.500' }}
|
_hover={{ color: 'red.500' }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedDatasets((state) =>
|
setSelectedDatasets((state) =>
|
||||||
state.filter((kb) => kb.datasetId !== item._id)
|
state.filter((dataset) => dataset.datasetId !== item._id)
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -141,7 +141,9 @@ export const DatasetSelectModal = ({
|
|||||||
if (item.type === DatasetTypeEnum.folder) {
|
if (item.type === DatasetTypeEnum.folder) {
|
||||||
setParentId(item._id);
|
setParentId(item._id);
|
||||||
} else {
|
} else {
|
||||||
const vectorModel = selectedDatasets[0]?.vectorModel?.model;
|
const vectorModel = datasets.find(
|
||||||
|
(dataset) => dataset._id === selectedDatasets[0]?.datasetId
|
||||||
|
)?.vectorModel?.model;
|
||||||
|
|
||||||
if (vectorModel && vectorModel !== item.vectorModel.model) {
|
if (vectorModel && vectorModel !== item.vectorModel.model) {
|
||||||
return toast({
|
return toast({
|
||||||
@@ -149,10 +151,7 @@ export const DatasetSelectModal = ({
|
|||||||
title: t('dataset.Select Dataset Tips')
|
title: t('dataset.Select Dataset Tips')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setSelectedDatasets((state) => [
|
setSelectedDatasets((state) => [...state, { datasetId: item._id }]);
|
||||||
...state,
|
|
||||||
{ datasetId: item._id, vectorModel: item.vectorModel }
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@@ -26,6 +26,8 @@ import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants
|
|||||||
import { checkInputIsReference } from '@fastgpt/global/core/workflow/utils';
|
import { checkInputIsReference } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext, getWorkflowStore } from '../../context';
|
import { WorkflowContext, getWorkflowStore } from '../../context';
|
||||||
|
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||||
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
|
||||||
const MyRightDrawer = dynamic(
|
const MyRightDrawer = dynamic(
|
||||||
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
|
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
|
||||||
@@ -109,15 +111,23 @@ export const useDebug = () => {
|
|||||||
const runtimeNode = runtimeNodes.find((node) => node.nodeId === runtimeNodeId);
|
const runtimeNode = runtimeNodes.find((node) => node.nodeId === runtimeNodeId);
|
||||||
|
|
||||||
if (!runtimeNode) return <></>;
|
if (!runtimeNode) return <></>;
|
||||||
const referenceInputs = runtimeNode.inputs.filter((input) => {
|
const renderInputs = runtimeNode.inputs.filter((input) => {
|
||||||
|
if (runtimeNode.flowNodeType === FlowNodeTypeEnum.pluginInput) return true;
|
||||||
if (checkInputIsReference(input)) return true;
|
if (checkInputIsReference(input)) return true;
|
||||||
if (input.required && !input.value) return true;
|
if (input.required && !input.value) return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const { register, getValues, setValue, handleSubmit } = useForm<Record<string, any>>({
|
const { register, getValues, setValue, handleSubmit } = useForm<Record<string, any>>({
|
||||||
defaultValues: referenceInputs.reduce((acc, input) => {
|
defaultValues: renderInputs.reduce((acc: Record<string, any>, input) => {
|
||||||
//@ts-ignore
|
const isReference = checkInputIsReference(input);
|
||||||
|
if (isReference) {
|
||||||
acc[input.key] = undefined;
|
acc[input.key] = undefined;
|
||||||
|
} else if (typeof input.value === 'object') {
|
||||||
|
acc[input.key] = JSON.stringify(input.value, null, 2);
|
||||||
|
} else {
|
||||||
|
acc[input.key] = input.value;
|
||||||
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
});
|
});
|
||||||
@@ -153,22 +163,14 @@ export const useDebug = () => {
|
|||||||
iconSrc="core/workflow/debugBlue"
|
iconSrc="core/workflow/debugBlue"
|
||||||
title={t('core.workflow.Debug Node')}
|
title={t('core.workflow.Debug Node')}
|
||||||
maxW={['90vw', '35vw']}
|
maxW={['90vw', '35vw']}
|
||||||
|
px={0}
|
||||||
>
|
>
|
||||||
<Flex flexDirection={'column'} h={'100%'}>
|
<Flex flexDirection={'column'} h={'100%'}>
|
||||||
<Box flex={'1 0 0'} overflow={'auto'}>
|
<Box flex={'1 0 0'} overflow={'auto'} px={6}>
|
||||||
{referenceInputs.map((input) => {
|
{renderInputs.map((input) => {
|
||||||
const required = input.required || false;
|
const required = input.required || false;
|
||||||
return (
|
console.log(input.valueType);
|
||||||
<Box key={input.key} _notLast={{ mb: 4 }} px={1}>
|
const RenderInput = (() => {
|
||||||
<Box display={'inline-block'} position={'relative'} mb={1}>
|
|
||||||
{required && (
|
|
||||||
<Box position={'absolute'} right={-2} top={-1} color={'red.600'}>
|
|
||||||
*
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{t(input.debugLabel || input.label)}
|
|
||||||
</Box>
|
|
||||||
{(() => {
|
|
||||||
if (input.valueType === WorkflowIOValueTypeEnum.string) {
|
if (input.valueType === WorkflowIOValueTypeEnum.string) {
|
||||||
return (
|
return (
|
||||||
<Textarea
|
<Textarea
|
||||||
@@ -182,12 +184,7 @@ export const useDebug = () => {
|
|||||||
}
|
}
|
||||||
if (input.valueType === WorkflowIOValueTypeEnum.number) {
|
if (input.valueType === WorkflowIOValueTypeEnum.number) {
|
||||||
return (
|
return (
|
||||||
<NumberInput
|
<NumberInput step={input.step} min={input.min} max={input.max} bg={'myGray.50'}>
|
||||||
step={input.step}
|
|
||||||
min={input.min}
|
|
||||||
max={input.max}
|
|
||||||
bg={'myGray.50'}
|
|
||||||
>
|
|
||||||
<NumberInputField
|
<NumberInputField
|
||||||
{...register(input.key, {
|
{...register(input.key, {
|
||||||
required: input.required,
|
required: input.required,
|
||||||
@@ -204,8 +201,13 @@ export const useDebug = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (input.valueType === WorkflowIOValueTypeEnum.boolean) {
|
if (input.valueType === WorkflowIOValueTypeEnum.boolean) {
|
||||||
return <Switch size={'lg'} {...register(input.key)} />;
|
return (
|
||||||
|
<Box>
|
||||||
|
<Switch size={'lg'} {...register(input.key)} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
if (typeof input.value === 'string') {
|
||||||
return (
|
return (
|
||||||
<JsonEditor
|
<JsonEditor
|
||||||
bg={'myGray.50'}
|
bg={'myGray.50'}
|
||||||
@@ -217,9 +219,25 @@ export const useDebug = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return !!RenderInput ? (
|
||||||
|
<Box key={input.key} _notLast={{ mb: 4 }} px={1}>
|
||||||
|
<Flex alignItems={'center'} mb={1}>
|
||||||
|
<Box position={'relative'}>
|
||||||
|
{required && (
|
||||||
|
<Box position={'absolute'} right={-2} top={'-1px'} color={'red.600'}>
|
||||||
|
*
|
||||||
</Box>
|
</Box>
|
||||||
);
|
)}
|
||||||
|
{t(input.debugLabel || input.label)}
|
||||||
|
</Box>
|
||||||
|
{input.description && <QuestionTip ml={2} label={input.description} />}
|
||||||
|
</Flex>
|
||||||
|
{RenderInput}
|
||||||
|
</Box>
|
||||||
|
) : null;
|
||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
<Flex py={2} justifyContent={'flex-end'}>
|
<Flex py={2} justifyContent={'flex-end'}>
|
||||||
|
@@ -35,7 +35,7 @@ import { useContextSelector } from 'use-context-selector';
|
|||||||
import { WorkflowContext } from '../context';
|
import { WorkflowContext } from '../context';
|
||||||
|
|
||||||
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
|
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
|
||||||
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
const nodeTypes: Record<FlowNodeTypeEnum, any> = {
|
||||||
[FlowNodeTypeEnum.emptyNode]: NodeSimple,
|
[FlowNodeTypeEnum.emptyNode]: NodeSimple,
|
||||||
[FlowNodeTypeEnum.globalVariable]: NodeSimple,
|
[FlowNodeTypeEnum.globalVariable]: NodeSimple,
|
||||||
[FlowNodeTypeEnum.systemConfig]: dynamic(() => import('./nodes/NodeSystemConfig')),
|
[FlowNodeTypeEnum.systemConfig]: dynamic(() => import('./nodes/NodeSystemConfig')),
|
||||||
|
@@ -146,17 +146,9 @@ const NodePluginInput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
if (!input) return;
|
if (!input) return;
|
||||||
|
|
||||||
setEditField({
|
setEditField({
|
||||||
|
...input,
|
||||||
inputType: input.renderTypeList[0],
|
inputType: input.renderTypeList[0],
|
||||||
valueType: input.valueType,
|
isToolInput: !!input.toolDescription
|
||||||
key: input.key,
|
|
||||||
label: input.label,
|
|
||||||
description: input.description,
|
|
||||||
isToolInput: !!input.toolDescription,
|
|
||||||
defaultValue: input.defaultValue,
|
|
||||||
maxLength: input.maxLength,
|
|
||||||
max: input.max,
|
|
||||||
min: input.min,
|
|
||||||
dynamicParamDefaultValue: input.dynamicParamDefaultValue
|
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onEdit={({ data, changeKey }) => {
|
onEdit={({ data, changeKey }) => {
|
||||||
@@ -165,20 +157,14 @@ const NodePluginInput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
const output = outputs.find((output) => output.key === editField.key);
|
const output = outputs.find((output) => output.key === editField.key);
|
||||||
|
|
||||||
const newInput: FlowNodeInputItemType = {
|
const newInput: FlowNodeInputItemType = {
|
||||||
|
...data,
|
||||||
key: data.key,
|
key: data.key,
|
||||||
valueType: data.valueType,
|
|
||||||
label: data.label || '',
|
label: data.label || '',
|
||||||
renderTypeList: [data.inputType],
|
renderTypeList: [data.inputType],
|
||||||
required: data.required,
|
|
||||||
description: data.description,
|
|
||||||
toolDescription: data.isToolInput ? data.description : undefined,
|
toolDescription: data.isToolInput ? data.description : undefined,
|
||||||
canEdit: true,
|
canEdit: true,
|
||||||
value: data.defaultValue,
|
value: data.defaultValue,
|
||||||
editField: dynamicInputEditField,
|
editField: dynamicInputEditField
|
||||||
maxLength: data.maxLength,
|
|
||||||
max: data.max,
|
|
||||||
min: data.min,
|
|
||||||
dynamicParamDefaultValue: data.dynamicParamDefaultValue
|
|
||||||
};
|
};
|
||||||
const newOutput: FlowNodeOutputItemType = {
|
const newOutput: FlowNodeOutputItemType = {
|
||||||
...(output as FlowNodeOutputItemType),
|
...(output as FlowNodeOutputItemType),
|
||||||
|
@@ -24,6 +24,8 @@ import MySelect from '@fastgpt/web/components/common/MySelect';
|
|||||||
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput/index';
|
||||||
|
import { useI18n } from '@/web/context/I18n';
|
||||||
|
|
||||||
const JsonEditor = dynamic(() => import('@fastgpt/web/components/common/Textarea/JsonEditor'));
|
const JsonEditor = dynamic(() => import('@fastgpt/web/components/common/Textarea/JsonEditor'));
|
||||||
const EmptyTip = dynamic(() => import('@fastgpt/web/components/common/EmptyTip'));
|
const EmptyTip = dynamic(() => import('@fastgpt/web/components/common/EmptyTip'));
|
||||||
@@ -63,6 +65,7 @@ const FieldEditModal = ({
|
|||||||
onSubmit: (e: { data: EditNodeFieldType; changeKey: boolean }) => void;
|
onSubmit: (e: { data: EditNodeFieldType; changeKey: boolean }) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { workflowT } = useI18n();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const showDynamicInputSelect =
|
const showDynamicInputSelect =
|
||||||
!keys.includes(NodeInputKeyEnum.addInputParam) ||
|
!keys.includes(NodeInputKeyEnum.addInputParam) ||
|
||||||
@@ -274,7 +277,6 @@ const FieldEditModal = ({
|
|||||||
);
|
);
|
||||||
const onSubmitError = useCallback(
|
const onSubmitError = useCallback(
|
||||||
(e: Object) => {
|
(e: Object) => {
|
||||||
console.log(e);
|
|
||||||
for (const item of Object.values(e)) {
|
for (const item of Object.values(e)) {
|
||||||
if (item.message) {
|
if (item.message) {
|
||||||
toast({
|
toast({
|
||||||
@@ -293,7 +295,6 @@ const FieldEditModal = ({
|
|||||||
isOpen={true}
|
isOpen={true}
|
||||||
iconSrc="/imgs/workflow/extract.png"
|
iconSrc="/imgs/workflow/extract.png"
|
||||||
title={t('core.module.edit.Field Edit')}
|
title={t('core.module.edit.Field Edit')}
|
||||||
onClose={onClose}
|
|
||||||
maxW={['90vw', showInputTypeSelect ? '800px' : '400px']}
|
maxW={['90vw', showInputTypeSelect ? '800px' : '400px']}
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
overflow={'unset'}
|
overflow={'unset'}
|
||||||
@@ -364,6 +365,10 @@ const FieldEditModal = ({
|
|||||||
{/* input type config */}
|
{/* input type config */}
|
||||||
{showInputTypeSelect && (
|
{showInputTypeSelect && (
|
||||||
<Stack flex={1} gap={5}>
|
<Stack flex={1} gap={5}>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 70px'}>{workflowT('Field required')}</Box>
|
||||||
|
<Switch {...register('required')} />
|
||||||
|
</Flex>
|
||||||
{showToolInput && (
|
{showToolInput && (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box flex={'0 0 70px'}>工具参数</Box>
|
<Box flex={'0 0 70px'}>工具参数</Box>
|
||||||
@@ -426,10 +431,16 @@ const FieldEditModal = ({
|
|||||||
{showMaxLenInput && (
|
{showMaxLenInput && (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box flex={'0 0 70px'}>{t('core.module.Max Length')}</Box>
|
<Box flex={'0 0 70px'}>{t('core.module.Max Length')}</Box>
|
||||||
<Input
|
<MyNumberInput
|
||||||
|
flex={'1 0 0'}
|
||||||
bg={'myGray.50'}
|
bg={'myGray.50'}
|
||||||
placeholder={t('core.module.Max Length placeholder')}
|
placeholder={t('core.module.Max Length placeholder')}
|
||||||
{...register('maxLength')}
|
value={maxLength}
|
||||||
|
onChange={(e) => {
|
||||||
|
// @ts-ignore
|
||||||
|
setValue('maxLength', e);
|
||||||
|
}}
|
||||||
|
// {...register('maxLength')}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
@@ -437,11 +448,27 @@ const FieldEditModal = ({
|
|||||||
<>
|
<>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box flex={'0 0 70px'}>{t('core.module.Max Value')}</Box>
|
<Box flex={'0 0 70px'}>{t('core.module.Max Value')}</Box>
|
||||||
<Input bg={'myGray.50'} type={'number'} {...register('max')} />
|
<MyNumberInput
|
||||||
|
flex={'1 0 0'}
|
||||||
|
bg={'myGray.50'}
|
||||||
|
value={watch('max')}
|
||||||
|
onChange={(e) => {
|
||||||
|
// @ts-ignore
|
||||||
|
setValue('max', e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box flex={'0 0 70px'}>{t('core.module.Min Value')}</Box>
|
<Box flex={'0 0 70px'}>{t('core.module.Min Value')}</Box>
|
||||||
<Input bg={'myGray.50'} type={'number'} {...register('min')} />
|
<MyNumberInput
|
||||||
|
flex={'1 0 0'}
|
||||||
|
bg={'myGray.50'}
|
||||||
|
value={watch('min')}
|
||||||
|
onChange={(e) => {
|
||||||
|
// @ts-ignore
|
||||||
|
setValue('min', e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@@ -55,7 +55,6 @@ const NodeCard = (props: Props) => {
|
|||||||
maxW = '600px',
|
maxW = '600px',
|
||||||
nodeId,
|
nodeId,
|
||||||
flowNodeType,
|
flowNodeType,
|
||||||
inputs,
|
|
||||||
selected,
|
selected,
|
||||||
menuForbid,
|
menuForbid,
|
||||||
isTool = false,
|
isTool = false,
|
||||||
|
@@ -90,17 +90,13 @@ const InputLabel = ({ nodeId, input }: Props) => {
|
|||||||
_hover={{ color: 'primary.500' }}
|
_hover={{ color: 'primary.500' }}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setEditField({
|
setEditField({
|
||||||
|
...input,
|
||||||
inputType: renderTypeList[0],
|
inputType: renderTypeList[0],
|
||||||
valueType: valueType,
|
valueType: valueType,
|
||||||
key,
|
key,
|
||||||
label,
|
label,
|
||||||
description,
|
description,
|
||||||
isToolInput: !!toolDescription,
|
isToolInput: !!toolDescription
|
||||||
defaultValue: input.defaultValue,
|
|
||||||
maxLength: input.maxLength,
|
|
||||||
max: input.max,
|
|
||||||
min: input.min,
|
|
||||||
dynamicParamDefaultValue: input.dynamicParamDefaultValue
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@@ -106,7 +106,6 @@ const VariableTable = ({
|
|||||||
keys={keys}
|
keys={keys}
|
||||||
onClose={onCloseFieldEdit}
|
onClose={onCloseFieldEdit}
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
console.log(e);
|
|
||||||
if (!!createField && onCreate) {
|
if (!!createField && onCreate) {
|
||||||
onCreate(e);
|
onCreate(e);
|
||||||
} else if (!!editField && onEdit) {
|
} else if (!!editField && onEdit) {
|
||||||
|
@@ -322,7 +322,6 @@ const WorkflowContextProvider = ({
|
|||||||
item.key === props.key ? props.value : item
|
item.key === props.key ? props.value : item
|
||||||
);
|
);
|
||||||
} else if (type === 'replaceInput') {
|
} else if (type === 'replaceInput') {
|
||||||
onDelEdge({ nodeId, targetHandle: getHandleId(nodeId, 'target', props.key) });
|
|
||||||
const oldInputIndex = node.data.inputs.findIndex((item) => item.key === props.key);
|
const oldInputIndex = node.data.inputs.findIndex((item) => item.key === props.key);
|
||||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -351,7 +350,6 @@ const WorkflowContextProvider = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type === 'delInput') {
|
} else if (type === 'delInput') {
|
||||||
onDelEdge({ nodeId, targetHandle: getHandleId(nodeId, 'target', props.key) });
|
|
||||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
||||||
} else if (type === 'updateOutput') {
|
} else if (type === 'updateOutput') {
|
||||||
updateObj.outputs = node.data.outputs.map((item) =>
|
updateObj.outputs = node.data.outputs.map((item) =>
|
||||||
|
@@ -24,6 +24,15 @@ export const flowNode2StoreNodes = ({
|
|||||||
outputs: item.data.outputs,
|
outputs: item.data.outputs,
|
||||||
pluginId: item.data.pluginId
|
pluginId: item.data.pluginId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// get all handle
|
||||||
|
const reactFlowViewport = document.querySelector('.react-flow__viewport');
|
||||||
|
// Gets the value of data-handleid on all elements below it whose data-handleid is not empty
|
||||||
|
const handleList =
|
||||||
|
reactFlowViewport?.querySelectorAll('[data-handleid]:not([data-handleid=""])') || [];
|
||||||
|
const handleIdList = Array.from(handleList).map(
|
||||||
|
(item) => item.getAttribute('data-handleid') || ''
|
||||||
|
);
|
||||||
const formatEdges: StoreEdgeItemType[] = edges
|
const formatEdges: StoreEdgeItemType[] = edges
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
source: item.source,
|
source: item.source,
|
||||||
@@ -31,7 +40,11 @@ export const flowNode2StoreNodes = ({
|
|||||||
sourceHandle: item.sourceHandle || '',
|
sourceHandle: item.sourceHandle || '',
|
||||||
targetHandle: item.targetHandle || ''
|
targetHandle: item.targetHandle || ''
|
||||||
}))
|
}))
|
||||||
.filter((item) => item.sourceHandle && item.targetHandle);
|
.filter((item) => item.sourceHandle && item.targetHandle)
|
||||||
|
.filter(
|
||||||
|
// Filter out edges that do not have both sourceHandle and targetHandle
|
||||||
|
(item) => handleIdList.includes(item.sourceHandle) && handleIdList.includes(item.targetHandle)
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes: formatNodes,
|
nodes: formatNodes,
|
||||||
|
@@ -131,7 +131,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
[isShowVersionHistories, edges, updateAppDetail, app._id, t]
|
[isV2Workflow, isShowVersionHistories, edges, updateAppDetail, app._id, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onclickPublish = useCallback(async () => {
|
const onclickPublish = useCallback(async () => {
|
||||||
|
@@ -196,7 +196,10 @@ export async function getServerSideProps(context: any) {
|
|||||||
const currentTab = context?.query?.currentTab || TabEnum.simpleEdit;
|
const currentTab = context?.query?.currentTab || TabEnum.simpleEdit;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: { currentTab, ...(await serviceSideProps(context, ['app', 'file', 'publish'])) }
|
props: {
|
||||||
|
currentTab,
|
||||||
|
...(await serviceSideProps(context, ['app', 'file', 'publish', 'workflow']))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -91,7 +91,7 @@ export async function getServerSideProps(context: any) {
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
pluginId: context?.query?.pluginId || '',
|
pluginId: context?.query?.pluginId || '',
|
||||||
...(await serviceSideProps(context))
|
...(await serviceSideProps(context, ['app', 'workflow']))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'
|
|||||||
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
import { useWorkflowStore } from '@/web/core/workflow/store/workflow';
|
import { useWorkflowStore } from '@/web/core/workflow/store/workflow';
|
||||||
import { EditFormType } from './type';
|
import { EditFormType } from './type';
|
||||||
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||||
|
|
||||||
export const defaultForm: EditFormType = {
|
export const defaultForm: EditFormType = {
|
||||||
@@ -33,7 +34,7 @@ export const defaultForm: EditFormType = {
|
|||||||
nodeId: nanoid(),
|
nodeId: nanoid(),
|
||||||
name: '自定义插件输入',
|
name: '自定义插件输入',
|
||||||
avatar: '/imgs/workflow/input.png',
|
avatar: '/imgs/workflow/input.png',
|
||||||
flowNodeType: 'pluginInput',
|
flowNodeType: FlowNodeTypeEnum.pluginInput,
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
position: {
|
position: {
|
||||||
x: 616.4226348688949,
|
x: 616.4226348688949,
|
||||||
@@ -47,7 +48,7 @@ export const defaultForm: EditFormType = {
|
|||||||
nodeId: nanoid(),
|
nodeId: nanoid(),
|
||||||
name: '自定义插件输出',
|
name: '自定义插件输出',
|
||||||
avatar: '/imgs/workflow/output.png',
|
avatar: '/imgs/workflow/output.png',
|
||||||
flowNodeType: 'pluginOutput',
|
flowNodeType: FlowNodeTypeEnum.pluginOutput,
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
position: {
|
position: {
|
||||||
x: 1607.7142331269126,
|
x: 1607.7142331269126,
|
||||||
|
2
projects/app/src/types/i18n.d.ts
vendored
2
projects/app/src/types/i18n.d.ts
vendored
@@ -4,6 +4,7 @@ import dataset from '../../i18n/zh/dataset.json';
|
|||||||
import app from '../../i18n/zh/app.json';
|
import app from '../../i18n/zh/app.json';
|
||||||
import file from '../../i18n/zh/file.json';
|
import file from '../../i18n/zh/file.json';
|
||||||
import publish from '../../i18n/zh/publish.json';
|
import publish from '../../i18n/zh/publish.json';
|
||||||
|
import workflow from '../../i18n/zh/workflow.json';
|
||||||
|
|
||||||
export interface I18nNamespaces {
|
export interface I18nNamespaces {
|
||||||
common: typeof common;
|
common: typeof common;
|
||||||
@@ -11,6 +12,7 @@ export interface I18nNamespaces {
|
|||||||
app: typeof app;
|
app: typeof app;
|
||||||
file: typeof file;
|
file: typeof file;
|
||||||
publish: typeof publish;
|
publish: typeof publish;
|
||||||
|
workflow: typeof workflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type I18nNsType = (keyof I18nNamespaces)[];
|
export type I18nNsType = (keyof I18nNamespaces)[];
|
||||||
|
@@ -8,6 +8,7 @@ type I18nContextType = {
|
|||||||
datasetT: TFunction<['dataset'], undefined>;
|
datasetT: TFunction<['dataset'], undefined>;
|
||||||
fileT: TFunction<['file'], undefined>;
|
fileT: TFunction<['file'], undefined>;
|
||||||
publishT: TFunction<['publish'], undefined>;
|
publishT: TFunction<['publish'], undefined>;
|
||||||
|
workflowT: TFunction<['workflow'], undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const I18nContext = createContext<I18nContextType>({
|
export const I18nContext = createContext<I18nContextType>({
|
||||||
@@ -21,6 +22,7 @@ const I18nContextProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
const { t: datasetT } = useTranslation('dataset');
|
const { t: datasetT } = useTranslation('dataset');
|
||||||
const { t: fileT } = useTranslation('file');
|
const { t: fileT } = useTranslation('file');
|
||||||
const { t: publishT } = useTranslation('publish');
|
const { t: publishT } = useTranslation('publish');
|
||||||
|
const { t: workflowT } = useTranslation('workflow');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<I18nContext.Provider
|
<I18nContext.Provider
|
||||||
@@ -29,7 +31,8 @@ const I18nContextProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
appT,
|
appT,
|
||||||
datasetT,
|
datasetT,
|
||||||
fileT,
|
fileT,
|
||||||
publishT
|
publishT,
|
||||||
|
workflowT
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
import { AppItemType } from '@/types/app';
|
import { AppItemType } from '@/types/app';
|
||||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import {
|
||||||
|
FlowNodeInputTypeEnum,
|
||||||
|
FlowNodeTypeEnum
|
||||||
|
} from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
|
||||||
// template
|
// template
|
||||||
export const appTemplates: (AppItemType & {
|
export const appTemplates: (AppItemType & {
|
||||||
@@ -21,7 +24,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '系统配置',
|
name: '系统配置',
|
||||||
intro: '可以配置应用的系统参数',
|
intro: '可以配置应用的系统参数',
|
||||||
avatar: '/imgs/workflow/userGuide.png',
|
avatar: '/imgs/workflow/userGuide.png',
|
||||||
flowNodeType: 'userGuide',
|
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
||||||
position: {
|
position: {
|
||||||
x: 531.2422736065552,
|
x: 531.2422736065552,
|
||||||
y: -486.7611729549753
|
y: -486.7611729549753
|
||||||
@@ -84,7 +87,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '流程开始',
|
name: '流程开始',
|
||||||
intro: '',
|
intro: '',
|
||||||
avatar: '/imgs/workflow/userChatInput.svg',
|
avatar: '/imgs/workflow/userChatInput.svg',
|
||||||
flowNodeType: 'workflowStart',
|
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
||||||
position: {
|
position: {
|
||||||
x: 558.4082376415505,
|
x: 558.4082376415505,
|
||||||
y: 123.72387429194112
|
y: 123.72387429194112
|
||||||
@@ -115,7 +118,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: '/imgs/workflow/AI.png',
|
||||||
flowNodeType: 'chatNode',
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1097.7317280958762,
|
x: 1097.7317280958762,
|
||||||
@@ -251,7 +254,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '系统配置',
|
name: '系统配置',
|
||||||
intro: '可以配置应用的系统参数',
|
intro: '可以配置应用的系统参数',
|
||||||
avatar: '/imgs/workflow/userGuide.png',
|
avatar: '/imgs/workflow/userGuide.png',
|
||||||
flowNodeType: 'userGuide',
|
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
||||||
position: {
|
position: {
|
||||||
x: 496.57560693988853,
|
x: 496.57560693988853,
|
||||||
y: -490.7611729549753
|
y: -490.7611729549753
|
||||||
@@ -331,7 +334,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '流程开始',
|
name: '流程开始',
|
||||||
intro: '',
|
intro: '',
|
||||||
avatar: '/imgs/workflow/userChatInput.svg',
|
avatar: '/imgs/workflow/userChatInput.svg',
|
||||||
flowNodeType: 'workflowStart',
|
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
||||||
position: {
|
position: {
|
||||||
x: 558.4082376415505,
|
x: 558.4082376415505,
|
||||||
y: 123.72387429194112
|
y: 123.72387429194112
|
||||||
@@ -362,7 +365,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: '/imgs/workflow/AI.png',
|
||||||
flowNodeType: 'chatNode',
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1097.7317280958762,
|
x: 1097.7317280958762,
|
||||||
@@ -498,7 +501,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '系统配置',
|
name: '系统配置',
|
||||||
intro: '可以配置应用的系统参数',
|
intro: '可以配置应用的系统参数',
|
||||||
avatar: '/imgs/workflow/userGuide.png',
|
avatar: '/imgs/workflow/userGuide.png',
|
||||||
flowNodeType: 'userGuide',
|
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
||||||
position: {
|
position: {
|
||||||
x: 531.2422736065552,
|
x: 531.2422736065552,
|
||||||
y: -486.7611729549753
|
y: -486.7611729549753
|
||||||
@@ -561,7 +564,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '流程开始',
|
name: '流程开始',
|
||||||
intro: '',
|
intro: '',
|
||||||
avatar: '/imgs/workflow/userChatInput.svg',
|
avatar: '/imgs/workflow/userChatInput.svg',
|
||||||
flowNodeType: 'workflowStart',
|
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
||||||
position: {
|
position: {
|
||||||
x: 558.4082376415505,
|
x: 558.4082376415505,
|
||||||
y: 123.72387429194112
|
y: 123.72387429194112
|
||||||
@@ -592,7 +595,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: '/imgs/workflow/AI.png',
|
||||||
flowNodeType: 'chatNode',
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1638.509551404687,
|
x: 1638.509551404687,
|
||||||
@@ -712,7 +715,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '知识库搜索',
|
name: '知识库搜索',
|
||||||
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
||||||
avatar: '/imgs/workflow/db.png',
|
avatar: '/imgs/workflow/db.png',
|
||||||
flowNodeType: 'datasetSearchNode',
|
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 918.5901682164496,
|
x: 918.5901682164496,
|
||||||
@@ -826,7 +829,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '系统配置',
|
name: '系统配置',
|
||||||
intro: '可以配置应用的系统参数',
|
intro: '可以配置应用的系统参数',
|
||||||
avatar: '/imgs/workflow/userGuide.png',
|
avatar: '/imgs/workflow/userGuide.png',
|
||||||
flowNodeType: 'userGuide',
|
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
||||||
position: {
|
position: {
|
||||||
x: 531.2422736065552,
|
x: 531.2422736065552,
|
||||||
y: -486.7611729549753
|
y: -486.7611729549753
|
||||||
@@ -889,7 +892,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '流程开始',
|
name: '流程开始',
|
||||||
intro: '',
|
intro: '',
|
||||||
avatar: '/imgs/workflow/userChatInput.svg',
|
avatar: '/imgs/workflow/userChatInput.svg',
|
||||||
flowNodeType: 'workflowStart',
|
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
||||||
position: {
|
position: {
|
||||||
x: 558.4082376415505,
|
x: 558.4082376415505,
|
||||||
y: 123.72387429194112
|
y: 123.72387429194112
|
||||||
@@ -920,7 +923,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: '/imgs/workflow/AI.png',
|
||||||
flowNodeType: 'chatNode',
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 2701.1267277679685,
|
x: 2701.1267277679685,
|
||||||
@@ -1041,7 +1044,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
intro:
|
intro:
|
||||||
'根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题',
|
'根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题',
|
||||||
avatar: '/imgs/workflow/cq.png',
|
avatar: '/imgs/workflow/cq.png',
|
||||||
flowNodeType: 'classifyQuestion',
|
flowNodeType: FlowNodeTypeEnum.classifyQuestion,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1020.9667229609946,
|
x: 1020.9667229609946,
|
||||||
@@ -1123,7 +1126,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
intro:
|
intro:
|
||||||
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
|
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
|
||||||
avatar: '/imgs/workflow/reply.png',
|
avatar: '/imgs/workflow/reply.png',
|
||||||
flowNodeType: 'answerNode',
|
flowNodeType: FlowNodeTypeEnum.answerNode,
|
||||||
position: {
|
position: {
|
||||||
x: 1874.9167551056487,
|
x: 1874.9167551056487,
|
||||||
y: 434.98431875888207
|
y: 434.98431875888207
|
||||||
@@ -1148,7 +1151,7 @@ export const appTemplates: (AppItemType & {
|
|||||||
name: '知识库搜索',
|
name: '知识库搜索',
|
||||||
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
||||||
avatar: '/imgs/workflow/db.png',
|
avatar: '/imgs/workflow/db.png',
|
||||||
flowNodeType: 'datasetSearchNode',
|
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1851.010152279949,
|
x: 1851.010152279949,
|
||||||
|
@@ -75,7 +75,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
name: '流程开始',
|
name: '流程开始',
|
||||||
intro: '',
|
intro: '',
|
||||||
avatar: '/imgs/workflow/userChatInput.svg',
|
avatar: '/imgs/workflow/userChatInput.svg',
|
||||||
flowNodeType: 'workflowStart',
|
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
||||||
position: {
|
position: {
|
||||||
x: 558.4082376415505,
|
x: 558.4082376415505,
|
||||||
y: 123.72387429194112
|
y: 123.72387429194112
|
||||||
@@ -111,7 +111,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: '/imgs/workflow/AI.png',
|
||||||
flowNodeType: 'chatNode',
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1106.3238387960757,
|
x: 1106.3238387960757,
|
||||||
@@ -244,7 +244,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: '/imgs/workflow/AI.png',
|
||||||
flowNodeType: 'chatNode',
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1638.509551404687,
|
x: 1638.509551404687,
|
||||||
@@ -364,7 +364,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
name: '知识库搜索',
|
name: '知识库搜索',
|
||||||
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
||||||
avatar: '/imgs/workflow/db.png',
|
avatar: '/imgs/workflow/db.png',
|
||||||
flowNodeType: 'datasetSearchNode',
|
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 918.5901682164496,
|
x: 918.5901682164496,
|
||||||
@@ -483,7 +483,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
name: '知识库搜索',
|
name: '知识库搜索',
|
||||||
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容',
|
||||||
avatar: '/imgs/workflow/db.png',
|
avatar: '/imgs/workflow/db.png',
|
||||||
flowNodeType: 'datasetSearchNode',
|
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 500,
|
x: 500,
|
||||||
@@ -626,7 +626,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
name: '工具调用(实验)',
|
name: '工具调用(实验)',
|
||||||
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
||||||
avatar: '/imgs/workflow/tool.svg',
|
avatar: '/imgs/workflow/tool.svg',
|
||||||
flowNodeType: 'tools',
|
flowNodeType: FlowNodeTypeEnum.tools,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
position: {
|
position: {
|
||||||
x: 1062.1738942532802,
|
x: 1062.1738942532802,
|
||||||
|
@@ -70,7 +70,9 @@ export const FlowValueTypeMap = {
|
|||||||
[WorkflowIOValueTypeEnum.selectDataset]: {
|
[WorkflowIOValueTypeEnum.selectDataset]: {
|
||||||
label: '选择知识库',
|
label: '选择知识库',
|
||||||
value: WorkflowIOValueTypeEnum.selectDataset,
|
value: WorkflowIOValueTypeEnum.selectDataset,
|
||||||
description: ''
|
description: `{
|
||||||
|
datasetId: string;
|
||||||
|
}`
|
||||||
},
|
},
|
||||||
[WorkflowIOValueTypeEnum.any]: {
|
[WorkflowIOValueTypeEnum.any]: {
|
||||||
label: 'any',
|
label: 'any',
|
||||||
|
@@ -323,7 +323,12 @@ export const updateFlowNodeVersion = (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedNode: FlowNodeItemType = { ...node, ...template, name: node.name };
|
const updatedNode: FlowNodeItemType = {
|
||||||
|
...node,
|
||||||
|
...template,
|
||||||
|
name: node.name,
|
||||||
|
intro: node.intro
|
||||||
|
};
|
||||||
|
|
||||||
if (node.inputs && template.inputs) {
|
if (node.inputs && template.inputs) {
|
||||||
updatedNode.inputs = updateArrayBasedOnTemplate(node.inputs, template.inputs);
|
updatedNode.inputs = updateArrayBasedOnTemplate(node.inputs, template.inputs);
|
||||||
|
Reference in New Issue
Block a user