Fix 4.8 node (#1370)

* perf: runtime props

* fix: Plugin run faied in debug mode

* perf: variable update

* fix: ts

* perf: variable ui
This commit is contained in:
Archer
2024-05-06 17:13:50 +08:00
committed by GitHub
parent 5bb9c550f6
commit eef609a063
37 changed files with 398 additions and 249 deletions

View File

@@ -160,7 +160,7 @@ const ChatBox = (
/* variable */
const filterVariableModules = useMemo(
() => variableModules.filter((item) => item.type !== VariableInputEnum.external),
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
[variableModules]
);

View File

@@ -173,7 +173,7 @@ const VariableEdit = ({
maxW={['90vw', '500px']}
>
<ModalBody>
{variableType !== VariableInputEnum.external && (
{variableType !== VariableInputEnum.custom && (
<Flex alignItems={'center'}>
<Box w={'70px'}>{t('common.Require Input')}</Box>
<Switch {...registerEdit('variable.required')} />
@@ -197,7 +197,7 @@ const VariableEdit = ({
</Flex>
<Box mt={5} mb={2}>
{t('core.module.Field Type')}
{t('core.workflow.Variable.Variable type')}
</Box>
<MyRadio
gridGap={4}

View File

@@ -31,13 +31,13 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
import { ReferSelector, useReference } from './render/RenderInput/templates/Reference';
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
import { isReferenceValue } from '@fastgpt/global/core/workflow/utils';
const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { inputs = [], nodeId } = data;
const { t } = useTranslation();
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const updateList = useMemo(
@@ -65,175 +65,201 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
[inputs, nodeId, onChangeNode]
);
const menuList = [
{
renderType: FlowNodeInputTypeEnum.input,
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
label: t('core.workflow.inputType.Manual input')
},
{
renderType: FlowNodeInputTypeEnum.reference,
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.reference].icon,
label: t('core.workflow.inputType.Reference')
}
];
const Render = useMemo(() => {
const menuList = [
{
renderType: FlowNodeInputTypeEnum.input,
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
label: t('core.workflow.inputType.Manual input')
},
{
renderType: FlowNodeInputTypeEnum.reference,
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.reference].icon,
label: t('core.workflow.inputType.Reference')
}
];
return (
<NodeCard selected={selected} maxW={'1000px'} {...data}>
<Box px={4} pb={4}>
return (
<>
{updateList.map((updateItem, index) => {
const type = (() => {
const valueType = (() => {
const variable = updateItem.variable;
const variableNodeId = variable?.[0];
const variableNode = nodes.find((node) => node.id === variableNodeId);
const variableNode = nodeList.find((node) => node.nodeId === variableNodeId);
const systemVariables = getWorkflowGlobalVariables(nodeList, t);
const variableInput = !variableNode
? systemVariables.find((item) => item.key === variable?.[1])
: variableNode?.data.outputs.find((output) => output.id === variable?.[1]);
if (!variableInput) return 'any';
: variableNode.outputs.find((output) => output.id === variable?.[1]);
if (!variableInput) return WorkflowIOValueTypeEnum.any;
return variableInput.valueType;
})();
const renderTypeData = menuList.find((item) => item.renderType === updateItem.renderType);
const handleUpdate = (newValue: ReferenceValueProps | string) => {
if (Array.isArray(newValue)) {
if (isReferenceValue(newValue)) {
onUpdateList(
updateList.map((update, i) =>
i === index ? { ...update, value: newValue } : update
i === index ? { ...update, value: newValue as ReferenceValueProps } : update
)
);
} else {
onUpdateList(
updateList.map((update, i) =>
i === index ? { ...update, value: ['', newValue] } : update
i === index ? { ...update, value: ['', newValue as string] } : update
)
);
}
};
return (
<Flex key={index}>
<Container mt={4} w={'full'}>
<Flex alignItems={'center'}>
<Flex w={'60px'}>{t('core.workflow.variable')}</Flex>
<Reference
nodeId={nodeId}
variable={updateItem.variable}
onSelect={(value) => {
onUpdateList(
updateList.map((update, i) => {
if (i === index) {
return {
...update,
variable: value
};
}
return update;
})
);
<Container key={index} mt={4} w={'full'} mx={0}>
<Flex alignItems={'center'}>
<Flex w={'60px'}>{t('core.workflow.variable')}</Flex>
<Reference
nodeId={nodeId}
variable={updateItem.variable}
onSelect={(value) => {
onUpdateList(
updateList.map((update, i) => {
if (i === index) {
return {
...update,
value: ['', ''],
valueType,
variable: value
};
}
return update;
})
);
}}
/>
<Box flex={1} />
{updateList.length > 1 && (
<MyIcon
className="delete"
name={'delete'}
w={'14px'}
color={'myGray.600'}
cursor={'pointer'}
_hover={{ color: 'red.500' }}
position={'absolute'}
top={3}
right={3}
onClick={() => {
onUpdateList(updateList.filter((_, i) => i !== index));
}}
/>
<Box flex={1} />
{updateList.length > 1 && (
<MyIcon
className="delete"
name={'delete'}
w={'14px'}
color={'myGray.600'}
cursor={'pointer'}
ml={2}
_hover={{ color: 'red.500' }}
)}
</Flex>
<Flex mt={2} w={'full'} alignItems={'center'} className="nodrag">
<Flex w={'60px'}>
<Box>{t('core.workflow.value')}</Box>
<MyTooltip
label={
menuList.find((item) => item.renderType === updateItem.renderType)?.label
}
>
<Button
size={'xs'}
bg={'white'}
borderRadius={'xs'}
mx={2}
onClick={() => {
onUpdateList(updateList.filter((_, i) => i !== index));
onUpdateList(
updateList.map((update, i) => {
if (i === index) {
return {
...update,
value: ['', ''],
renderType:
updateItem.renderType === FlowNodeInputTypeEnum.input
? FlowNodeInputTypeEnum.reference
: FlowNodeInputTypeEnum.input
};
}
return update;
})
);
}}
/>
)}
</Flex>
<Flex mt={2} w={'full'} alignItems={'center'} className="nodrag">
<Flex w={'60px'}>
<Box>{t('core.workflow.value')}</Box>
<MyTooltip
label={
menuList.find((item) => item.renderType === updateItem.renderType)?.label
}
>
<Button
size={'xs'}
bg={'white'}
borderRadius={'xs'}
mx={2}
onClick={() => {
onUpdateList(
updateList.map((update, i) => {
if (i === index) {
return {
...update,
value: ['', ''],
renderType:
updateItem.renderType === FlowNodeInputTypeEnum.input
? FlowNodeInputTypeEnum.reference
: FlowNodeInputTypeEnum.input
};
}
return update;
})
);
}}
>
<MyIcon name={renderTypeData?.icon as any} w={'14px'} />
</Button>
</MyTooltip>
</Flex>
{updateItem.renderType === FlowNodeInputTypeEnum.reference ? (
<Reference
nodeId={nodeId}
variable={updateItem.value}
onSelect={handleUpdate}
/>
) : (
<>
{type === 'string' && (
<Textarea
<MyIcon name={renderTypeData?.icon as any} w={'14px'} />
</Button>
</MyTooltip>
</Flex>
{/* Render input components */}
{(() => {
if (updateItem.renderType === FlowNodeInputTypeEnum.reference) {
return (
<Reference
nodeId={nodeId}
variable={updateItem.value}
valueType={valueType}
onSelect={handleUpdate}
/>
);
}
if (valueType === WorkflowIOValueTypeEnum.string) {
return (
<Textarea
bg="white"
value={updateItem.value?.[1] || ''}
w="300px"
onChange={(e) => handleUpdate(e.target.value)}
/>
);
}
if (valueType === WorkflowIOValueTypeEnum.number) {
return (
<NumberInput value={Number(updateItem.value?.[1]) || 0}>
<NumberInputField
bg="white"
value={updateItem.value?.[1] || ''}
w="300px"
onChange={(e) => handleUpdate(e.target.value)}
/>
)}
{type === 'number' && (
<NumberInput value={Number(updateItem.value?.[1]) || 0}>
<NumberInputField
bg="white"
onChange={(e) => handleUpdate(e.target.value)}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
)}
{type === 'boolean' && (
<Switch
size="lg"
defaultChecked={updateItem.value?.[1] === 'true'}
onChange={(e) => handleUpdate(String(e.target.checked))}
/>
)}
{type !== 'string' && type !== 'number' && type !== 'boolean' && (
<JsonEditor
bg="white"
resize
w="300px"
value={updateItem.value?.[1] || ''}
onChange={(e) => handleUpdate(e)}
/>
)}
</>
)}
</Flex>
</Container>
</Flex>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
);
}
if (valueType === WorkflowIOValueTypeEnum.boolean) {
return (
<Switch
size="lg"
defaultChecked={updateItem.value?.[1] === 'true'}
onChange={(e) => handleUpdate(String(e.target.checked))}
/>
);
}
return (
<JsonEditor
bg="white"
resize
w="300px"
value={String(updateItem.value?.[1] || '')}
onChange={(e) => {
handleUpdate(e);
}}
/>
);
})()}
</Flex>
</Container>
);
})}
</>
);
}, [nodeId, nodeList, onUpdateList, t, updateList]);
return (
<NodeCard selected={selected} maxW={'1000px'} {...data}>
<Box px={4} pb={4}>
{Render}
<Flex className="nodrag" cursor={'default'} alignItems={'center'} position={'relative'}>
<Button
variant={'whiteBase'}
@@ -264,17 +290,19 @@ export default React.memo(NodeVariableUpdate);
const Reference = ({
nodeId,
variable,
valueType,
onSelect
}: {
nodeId: string;
variable?: ReferenceValueProps;
valueType?: WorkflowIOValueTypeEnum;
onSelect: (e: ReferenceValueProps) => void;
}) => {
const { t } = useTranslation();
const { referenceList, formatValue } = useReference({
nodeId,
valueType: WorkflowIOValueTypeEnum.any,
valueType,
value: variable
});

View File

@@ -90,7 +90,7 @@ export default React.memo(Reference);
export const useReference = ({
nodeId,
valueType,
valueType = WorkflowIOValueTypeEnum.any,
value
}: {
nodeId: string;

View File

@@ -36,7 +36,6 @@ import { createContext } from 'use-context-selector';
import { defaultRunningStatus } from './constants';
import { checkNodeRunStatus } from '@fastgpt/global/core/workflow/runtime/utils';
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
@@ -256,7 +255,11 @@ const WorkflowContextProvider = ({
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
const [hoverNodeId, setHoverNodeId] = useState<string>();
const nodeList = useCreation(() => nodes.map((node) => node.data), [nodes]);
const nodeListString = JSON.stringify(nodes.map((node) => node.data));
const nodeList = useMemo(
() => JSON.parse(nodeListString) as FlowNodeItemType[],
[nodeListString]
);
const hasToolNode = useMemo(() => {
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);

View File

@@ -5,7 +5,11 @@ import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/cons
import { responseWrite } from '@fastgpt/service/common/response';
import { pushChatUsage } from '@/service/support/wallet/usage/push';
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
import type { ChatItemType, ChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import type {
ChatItemType,
ChatItemValueItemType,
UserChatItemValueItemType
} from '@fastgpt/global/core/chat/type';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
@@ -13,10 +17,11 @@ import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/a
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
import { removeEmptyUserInput } from '@fastgpt/global/core/chat/utils';
export type Props = {
history: ChatItemType[];
prompt: ChatItemValueItemType[];
prompt: UserChatItemValueItemType[];
nodes: RuntimeNodeItemType[];
edges: RuntimeEdgeItemType[];
variables: Record<string, any>;
@@ -33,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
res.end();
});
const {
let {
nodes = [],
edges = [],
history = [],
@@ -66,8 +71,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// auth balance
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
const { text, files } = chatValue2RuntimePrompt(prompt);
/* start process */
const { flowResponses, flowUsages, newVariables } = await dispatchWorkFlow({
res,
@@ -78,11 +81,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
appId,
runtimeNodes: nodes,
runtimeEdges: edges,
variables: {
...variables,
userChatInput: text
},
inputFiles: files,
variables,
query: removeEmptyUserInput(prompt),
histories: history,
stream: true,
detail: true,

View File

@@ -57,7 +57,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...variables,
userChatInput: ''
},
inputFiles: [],
query: [],
histories: [],
stream: false,
detail: true,

View File

@@ -24,7 +24,10 @@ import { pushResult2Remote, addOutLinkUsage } from '@fastgpt/service/support/out
import requestIp from 'request-ip';
import { getUsageSourceByAuthType } from '@fastgpt/global/support/wallet/usage/tools';
import { authTeamSpaceToken } from '@/service/support/permission/auth/team';
import { filterPublicNodeResponseData } from '@fastgpt/global/core/chat/utils';
import {
filterPublicNodeResponseData,
removeEmptyUserInput
} from '@fastgpt/global/core/chat/utils';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { connectToDatabase } from '@/service/mongo';
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
@@ -192,11 +195,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
responseChatItemId,
runtimeNodes: storeNodes2RuntimeNodes(nodes, getDefaultEntryNodeIds(nodes)),
runtimeEdges: initWorkflowEdgeStatus(edges),
variables: {
...variables,
userChatInput: text
},
inputFiles: files,
variables,
query: removeEmptyUserInput(question.value),
histories: concatHistories,
stream,
detail,

View File

@@ -31,7 +31,7 @@ export const defaultForm: EditFormType = {
modules: [
{
nodeId: nanoid(),
name: '定义插件输入',
name: '定义插件输入',
avatar: '/imgs/workflow/input.png',
flowNodeType: 'pluginInput',
showStatus: false,
@@ -44,7 +44,7 @@ export const defaultForm: EditFormType = {
},
{
nodeId: nanoid(),
name: '定义插件输出',
name: '定义插件输出',
avatar: '/imgs/workflow/output.png',
flowNodeType: 'pluginOutput',
showStatus: false,

View File

@@ -1,6 +1,7 @@
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { delay } from '@fastgpt/global/common/system/utils';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
import {
getDefaultEntryNodeIds,
initWorkflowEdgeStatus,
@@ -34,9 +35,15 @@ export const getScheduleTriggerApp = async () => {
appId: String(app._id),
runtimeNodes: storeNodes2RuntimeNodes(app.modules, getDefaultEntryNodeIds(app.modules)),
runtimeEdges: initWorkflowEdgeStatus(app.edges),
variables: {
userChatInput: app.scheduledTriggerConfig?.defaultPrompt
},
variables: {},
query: [
{
type: ChatItemValueTypeEnum.text,
text: {
content: app.scheduledTriggerConfig?.defaultPrompt
}
}
],
histories: [],
stream: false,
detail: false,

View File

@@ -14,7 +14,7 @@ import { EmptyNode } from '@fastgpt/global/core/workflow/template/system/emptyNo
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { getGlobalVariableNode } from './adapt';
import { VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
import { VARIABLE_NODE_ID, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { EditorVariablePickerType } from '@fastgpt/web/components/common/Textarea/PromptEditor/type';
import {
@@ -243,7 +243,10 @@ export const getWorkflowGlobalVariables = (
): EditorVariablePickerType[] => {
const globalVariables = formatEditorVariablePickerIcon(
splitGuideModule(getGuideModule(nodes))?.variableModules || []
);
).map((item) => ({
...item,
valueType: WorkflowIOValueTypeEnum.string // 暂时都是字符串
}));
const systemVariables = getSystemVariables(t);