4.8.10 test (#2601)

* perf: workflow children run params

* feat: workflow userId

* fix: ui size

* perf: Markdown whitespace and ai images split

* fix: openai sdk ts
This commit is contained in:
Archer
2024-09-03 13:43:56 +08:00
committed by GitHub
parent 761e35c226
commit 9a57e94b79
43 changed files with 318 additions and 288 deletions

View File

@@ -13,10 +13,7 @@ import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { removeEmptyUserInput } from '@fastgpt/global/core/chat/utils';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import {
removePluginInputVariables,
updatePluginInputByVariables
} from '@fastgpt/global/core/workflow/utils';
import { updatePluginInputByVariables } from '@fastgpt/global/core/workflow/utils';
import { NextAPI } from '@/service/middleware/entry';
import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt';
import { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type';
@@ -89,7 +86,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
// Plugin need to replace inputs
if (isPlugin) {
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
variables = removePluginInputVariables(variables, runtimeNodes);
variables = {};
} else {
if (!userInput) {
throw new Error('Params Error');
@@ -109,10 +106,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
res,
requestOrigin: req.headers.origin,
mode: 'test',
teamId,
tmbId,
runningAppInfo: {
id: appId,
teamId,
tmbId
},
uid: tmbId,
user,
app,
runtimeNodes,
runtimeEdges: initWorkflowEdgeStatus(edges, chatMessages),
variables,

View File

@@ -43,10 +43,13 @@ async function handler(
res,
requestOrigin: req.headers.origin,
mode: 'debug',
teamId,
tmbId,
runningAppInfo: {
id: appId,
teamId,
tmbId
},
uid: tmbId,
user,
app,
runtimeNodes: nodes,
runtimeEdges: edges,
variables,

View File

@@ -52,18 +52,12 @@ import { NextAPI } from '@/service/middleware/entry';
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import {
removePluginInputVariables,
updatePluginInputByVariables
} from '@fastgpt/global/core/workflow/utils';
import { updatePluginInputByVariables } from '@fastgpt/global/core/workflow/utils';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import {
getPluginInputsFromStoreNodes,
getPluginRunContent
} from '@fastgpt/global/core/app/plugin/utils';
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
import { rewriteNodeOutputByHistories } from '@fastgpt/global/core/workflow/runtime/utils';
import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils';
import { getPluginRunUserQuery } from '@fastgpt/service/core/workflow/utils';
type FastGptWebChatProps = {
chatId?: string; // undefined: get histories from messages, '': new chat, 'xxxxx': get histories from db
@@ -193,21 +187,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
// Get obj=Human history
const userQuestion: UserChatItemType = (() => {
if (isPlugin) {
return {
dataId: getNanoid(24),
obj: ChatRoleEnum.Human,
value: [
{
type: ChatItemValueTypeEnum.text,
text: {
content: getPluginRunContent({
pluginInputs: getPluginInputsFromStoreNodes(app.modules),
variables
})
}
}
]
};
return getPluginRunUserQuery(app.modules, variables);
}
const latestHumanChat = chatMessages.pop() as UserChatItemType | undefined;
@@ -246,8 +226,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
if (isPlugin) {
// Assign values to runtimeNodes using variables
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
// Remove pluginInput fields from variables (they are not global variables)
variables = removePluginInputVariables(variables, runtimeNodes);
// Plugin runtime does not need global variables(It has been injected into the pluginInputNode)
variables = {};
}
runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes);
@@ -266,9 +246,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
requestOrigin: req.headers.origin,
mode: 'chat',
user,
teamId: String(teamId),
tmbId: String(tmbId),
app,
runningAppInfo: {
id: String(app._id),
teamId: String(app.teamId),
tmbId: String(app.tmbId)
},
uid: String(outLinkUserId || tmbId),
chatId,
responseChatItemId,
runtimeNodes,

View File

@@ -11,7 +11,8 @@ import {
Td,
Tbody,
useDisclosure,
Link
Link,
HStack
} from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useLoading } from '@fastgpt/web/hooks/useLoading';
@@ -66,26 +67,24 @@ const FeiShu = ({ appId }: { appId: string }) => {
return (
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
<Flex justifyContent={'space-between'} flexDirection="row">
<Flex alignItems={'center'}>
<HStack>
<Box fontWeight={'bold'} fontSize={['md', 'lg']}>
{t('common:core.app.publish.Fei shu bot publish')}
</Box>
{feConfigs?.docUrl && (
<Link
href={feConfigs.openAPIDocUrl || getDocPath('/docs/course/feishu')}
target={'_blank'}
ml={2}
color={'primary.500'}
fontSize={'sm'}
>
<Flex alignItems={'center'}>
<MyIcon name="book" mr="1" />
<MyIcon name="book" mr="1" w={'1rem'} />
{t('common:common.Read document')}
</Flex>
</Link>
)}
</Flex>
</HStack>
<Button
variant={'primary'}
colorScheme={'blue'}

View File

@@ -11,7 +11,8 @@ import {
Td,
Tbody,
useDisclosure,
Link
Link,
HStack
} from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useLoading } from '@fastgpt/web/hooks/useLoading';
@@ -67,7 +68,7 @@ const OffiAccount = ({ appId }: { appId: string }) => {
return (
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
<Flex justifyContent={'space-between'} flexDirection="row">
<Flex alignItems={'center'}>
<HStack>
<Box fontWeight={'bold'} fontSize={['md', 'lg']}>
{t('publish:official_account.name')}
</Box>
@@ -81,12 +82,12 @@ const OffiAccount = ({ appId }: { appId: string }) => {
fontSize={'sm'}
>
<Flex alignItems={'center'}>
<MyIcon name="book" mr="1" />
<MyIcon name="book" mr="1" w={'1rem'} />
{t('common:common.Read document')}
</Flex>
</Link>
)}
</Flex>
</HStack>
<Button
variant={'primary'}
colorScheme={'blue'}

View File

@@ -28,7 +28,7 @@ import SettingLLMModel from '@/components/core/ai/SettingLLMModel';
import type { SettingAIDataType } from '@fastgpt/global/core/app/type.d';
import DeleteIcon, { hoverDeleteStyles } from '@fastgpt/web/components/common/Icon/delete';
import { TTSTypeEnum } from '@/web/core/app/constants';
import { getSystemVariables } from '@/web/core/app/utils';
import { workflowSystemVariables } from '@/web/core/app/utils';
import { useI18n } from '@/web/context/I18n';
import { useContextSelector } from 'use-context-selector';
import { AppContext } from '@/pages/app/detail/components/context';
@@ -109,10 +109,11 @@ const EditForm = ({
const formatVariables = useMemo(
() =>
formatEditorVariablePickerIcon([
...getSystemVariables(t),
...workflowSystemVariables,
...(appForm.chatConfig.variables || [])
]).map((item) => ({
...item,
label: t(item.label as any),
parent: {
id: 'VARIABLE_NODE_ID',
label: t('common:core.module.Variable'),

View File

@@ -276,14 +276,13 @@ export function RenderHttpProps({
const variables = useMemo(() => {
const globalVariables = getWorkflowGlobalVariables({
nodes: nodeList,
chatConfig: appDetail.chatConfig,
t
chatConfig: appDetail.chatConfig
});
const nodeVariables = formatEditorVariablePickerIcon(getNodeDynamicInputs(nodeId));
return [...nodeVariables, ...globalVariables];
}, [appDetail.chatConfig, getNodeDynamicInputs, nodeId, nodeList, t]);
}, [appDetail.chatConfig, getNodeDynamicInputs, nodeId, nodeList]);
const variableText = useMemo(() => {
return variables

View File

@@ -348,10 +348,9 @@ const ConditionSelect = ({
return getRefData({
variable,
nodeList,
chatConfig: appDetail.chatConfig,
t
chatConfig: appDetail.chatConfig
});
}, [appDetail.chatConfig, nodeList, t, variable]);
}, [appDetail.chatConfig, nodeList, variable]);
const conditionList = useMemo(() => {
if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList;

View File

@@ -100,8 +100,7 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
const { valueType } = getRefData({
variable: updateItem.variable,
nodeList,
chatConfig: appDetail.chatConfig,
t
chatConfig: appDetail.chatConfig
});
const renderTypeData = menuList.find((item) => item.renderType === updateItem.renderType);
const handleUpdate = (newValue: ReferenceValueProps | string) => {

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useMemo } from 'react';
import { NodeProps } from 'reactflow';
import NodeCard from './render/NodeCard';
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
@@ -9,14 +9,17 @@ import { useTranslation } from 'next-i18next';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../context';
import { useCreation } from 'ahooks';
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
import { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io';
import {
chatHistoryValueDesc,
FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { AppContext } from '@/pages/app/detail/components/context';
import { workflowSystemVariables } from '@/web/core/app/utils';
import {
formatEditorVariablePickerIcon,
getAppChatConfig,
getGuideModule
} from '@fastgpt/global/core/workflow/utils';
import MyDivider from '@fastgpt/web/components/common/MyDivider';
const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation();
@@ -24,36 +27,42 @@ const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const { appDetail } = useContextSelector(AppContext, (v) => v);
const variablesOutputs = useCreation(() => {
const variables = getWorkflowGlobalVariables({
nodes: nodeList,
chatConfig: appDetail.chatConfig,
t
});
const customGlobalVariables = useCreation(() => {
const globalVariables = formatEditorVariablePickerIcon(
getAppChatConfig({
chatConfig: appDetail.chatConfig,
systemConfigNode: getGuideModule(nodeList),
isPublicFetch: true
})?.variables || []
);
return variables.map<FlowNodeOutputItemType>((item) => {
if (item.valueType === WorkflowIOValueTypeEnum.chatHistory) {
return {
id: item.key,
type: FlowNodeOutputTypeEnum.static,
key: item.key,
required: item.required,
valueType: item.valueType,
valueDesc: chatHistoryValueDesc,
label: item.label
};
}
return globalVariables.map<FlowNodeOutputItemType>((item) => {
return {
id: item.key,
type: FlowNodeOutputTypeEnum.static,
key: item.key,
required: item.required,
valueType: item.valueType || WorkflowIOValueTypeEnum.any,
label: item.label
label: t(item.label as any),
valueDesc: item.valueDesc
};
});
}, [nodeList, appDetail.chatConfig, t]);
const systemVariables = useMemo(
() =>
workflowSystemVariables.map((item) => ({
id: item.key,
type: FlowNodeOutputTypeEnum.static,
key: item.key,
required: item.required,
valueType: item.valueType || WorkflowIOValueTypeEnum.any,
label: t(item.label as any),
valueDesc: item.valueDesc
})),
[t]
);
return (
<NodeCard
minW={'240px'}
@@ -71,7 +80,14 @@ const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
</Container>
<Container>
<IOTitle text={t('common:core.module.Variable')} />
<RenderOutput nodeId={nodeId} flowOutputList={variablesOutputs} />
{customGlobalVariables.length > 0 && (
<>
<RenderOutput nodeId={nodeId} flowOutputList={customGlobalVariables} />
<MyDivider />
</>
)}
<RenderOutput nodeId={nodeId} flowOutputList={systemVariables} />
</Container>
</NodeCard>
);

View File

@@ -21,8 +21,7 @@ const JsonEditor = ({ inputs = [], item, nodeId }: RenderInputProps) => {
const variables = useCreation(() => {
const globalVariables = getWorkflowGlobalVariables({
nodes: nodeList,
chatConfig: appDetail.chatConfig,
t
chatConfig: appDetail.chatConfig
});
const nodeVariables = formatEditorVariablePickerIcon(getNodeDynamicInputs(nodeId));

View File

@@ -54,12 +54,11 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
const variables = useCreation(() => {
const globalVariables = getWorkflowGlobalVariables({
nodes: nodeList,
chatConfig: appDetail.chatConfig,
t
chatConfig: appDetail.chatConfig
});
return globalVariables;
}, [nodeList, t]);
}, [nodeList]);
const [selectTemplateData, setSelectTemplateData] = useState<{
title: string;

View File

@@ -48,7 +48,7 @@ const OutputLabel = ({ nodeId, output }: { nodeId: string; output: FlowNodeOutpu
)}
</Box>
);
}, [output.type, output.key, t, label, description, valueType, nodeId]);
}, [output.type, output.key, t, label, description, valueType, valueDesc, nodeId]);
return Render;
};

View File

@@ -134,12 +134,12 @@ const RenderOutput = ({
);
return (
<>
{renderOutputs.map((output) => {
{renderOutputs.map((output, i) => {
return output.label ? (
<FormLabel
key={output.key}
required={output.required}
_notLast={{ mb: 5 }}
mb={i === renderOutputs.length - 1 ? 0 : 5}
position={'relative'}
>
<OutputLabel nodeId={nodeId} output={output} />