mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-28 17:29:44 +00:00
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Box, useTheme, Flex, Image } from '@chakra-ui/react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Box, useTheme, Flex, Image, BoxProps } from '@chakra-ui/react';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { moduleTemplatesFlat } from '@fastgpt/global/core/workflow/template/constants';
|
||||
@@ -12,42 +12,68 @@ import Markdown from '../Markdown';
|
||||
import { QuoteList } from './QuoteModal';
|
||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
import { formatNumber } from '@fastgpt/global/common/math/tools';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
function RowRender({
|
||||
children,
|
||||
mb,
|
||||
label,
|
||||
...props
|
||||
}: { children: React.ReactNode; label: string } & BoxProps) {
|
||||
return (
|
||||
<Box mb={3}>
|
||||
<Box fontSize={['sm', 'md']} mb={mb} flex={'0 0 90px'}>
|
||||
{label}:
|
||||
</Box>
|
||||
<Box borderRadius={'sm'} fontSize={'sm'} bg={'myGray.50'} {...props}>
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
function Row({
|
||||
label,
|
||||
value,
|
||||
rawDom
|
||||
}: {
|
||||
label: string;
|
||||
value?: string | number | boolean;
|
||||
value?: string | number | boolean | object;
|
||||
rawDom?: React.ReactNode;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const val = value || rawDom;
|
||||
const strValue = `${value}`;
|
||||
const isCodeBlock = strValue.startsWith('~~~json');
|
||||
const isObject = typeof value === 'object';
|
||||
|
||||
return val !== undefined && val !== '' && val !== 'undefined' ? (
|
||||
<Box mb={3}>
|
||||
<Box fontSize={['sm', 'md']} mb={isCodeBlock ? 0 : 1} flex={'0 0 90px'}>
|
||||
{t(label)}:
|
||||
</Box>
|
||||
<Box
|
||||
borderRadius={'sm'}
|
||||
fontSize={'sm'}
|
||||
bg={'myGray.50'}
|
||||
{...(isCodeBlock
|
||||
? { transform: 'translateY(-3px)' }
|
||||
: value
|
||||
? { px: 3, py: 2, border: theme.borders.base }
|
||||
: {})}
|
||||
>
|
||||
{value && <Markdown source={strValue} />}
|
||||
const formatValue = useMemo(() => {
|
||||
if (isObject) {
|
||||
return `~~~json\n${JSON.stringify(value, null, 2)}`;
|
||||
}
|
||||
return `${value}`;
|
||||
}, [isObject, value]);
|
||||
|
||||
if (rawDom) {
|
||||
return (
|
||||
<RowRender label={label} mb={1}>
|
||||
{rawDom}
|
||||
</Box>
|
||||
</Box>
|
||||
) : null;
|
||||
</RowRender>
|
||||
);
|
||||
}
|
||||
|
||||
if (val === undefined || val === '' || val === 'undefined') return null;
|
||||
|
||||
return (
|
||||
<RowRender
|
||||
label={label}
|
||||
mb={isObject ? 0 : 1}
|
||||
{...(isObject
|
||||
? { transform: 'translateY(-3px)' }
|
||||
: value
|
||||
? { px: 3, py: 2, border: theme.borders.base }
|
||||
: {})}
|
||||
>
|
||||
<Markdown source={formatValue} />
|
||||
</RowRender>
|
||||
);
|
||||
}
|
||||
|
||||
const WholeResponseModal = ({
|
||||
@@ -98,6 +124,7 @@ export const ResponseBox = React.memo(function ResponseBox({
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { workflowT } = useI18n();
|
||||
|
||||
const list = useMemo(
|
||||
() =>
|
||||
@@ -251,47 +278,26 @@ export const ResponseBox = React.memo(function ResponseBox({
|
||||
label={t('core.chat.response.module extract description')}
|
||||
value={activeModule?.extractDescription}
|
||||
/>
|
||||
{activeModule?.extractResult && (
|
||||
<Row
|
||||
label={t('core.chat.response.module extract result')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.extractResult, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
<Row
|
||||
label={t('core.chat.response.module extract result')}
|
||||
value={activeModule?.extractResult}
|
||||
/>
|
||||
</>
|
||||
|
||||
{/* http */}
|
||||
<>
|
||||
{activeModule?.headers && (
|
||||
<Row
|
||||
label={'Headers'}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.headers, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.params && (
|
||||
<Row
|
||||
label={'Params'}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.params, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.body && (
|
||||
<Row label={'Body'} value={`~~~json\n${JSON.stringify(activeModule?.body, null, 2)}`} />
|
||||
)}
|
||||
{activeModule?.httpResult && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http result')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.httpResult, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
<Row label={'Headers'} value={activeModule?.headers} />
|
||||
<Row label={'Params'} value={activeModule?.params} />
|
||||
<Row label={'Body'} value={activeModule?.body} />
|
||||
<Row
|
||||
label={t('core.chat.response.module http result')}
|
||||
value={activeModule?.httpResult}
|
||||
/>
|
||||
</>
|
||||
|
||||
{/* plugin */}
|
||||
<>
|
||||
{activeModule?.pluginOutput && (
|
||||
<Row
|
||||
label={t('core.chat.response.plugin output')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.plugin output')} value={activeModule?.pluginOutput} />
|
||||
{activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.Plugin response detail')}
|
||||
@@ -310,6 +316,10 @@ export const ResponseBox = React.memo(function ResponseBox({
|
||||
rawDom={<ResponseBox response={activeModule.toolDetail} showDetail={showDetail} />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* code */}
|
||||
<Row label={workflowT('response.Custom inputs')} value={activeModule?.customInputs} />
|
||||
<Row label={workflowT('response.Custom outputs')} value={activeModule?.customOutputs} />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
@@ -58,7 +58,8 @@ const nodeTypes: Record<FlowNodeTypeEnum, any> = {
|
||||
),
|
||||
[FlowNodeTypeEnum.lafModule]: dynamic(() => import('./nodes/NodeLaf')),
|
||||
[FlowNodeTypeEnum.ifElseNode]: dynamic(() => import('./nodes/NodeIfElse')),
|
||||
[FlowNodeTypeEnum.variableUpdate]: dynamic(() => import('./nodes/NodeVariableUpdate'))
|
||||
[FlowNodeTypeEnum.variableUpdate]: dynamic(() => import('./nodes/NodeVariableUpdate')),
|
||||
[FlowNodeTypeEnum.code]: dynamic(() => import('./nodes/NodeCode'))
|
||||
};
|
||||
const edgeTypes = {
|
||||
[EDGE_TYPE]: ButtonEdge
|
||||
|
@@ -0,0 +1,107 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from './render/NodeCard';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import Container from '../components/Container';
|
||||
import RenderInput from './render/RenderInput';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import RenderToolInput from './render/RenderToolInput';
|
||||
import RenderOutput from './render/RenderOutput';
|
||||
import CodeEditor from '@fastgpt/web/components/common/Textarea/CodeEditor';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { JS_TEMPLATE } from '@fastgpt/global/core/workflow/template/system/sandbox/constants';
|
||||
|
||||
const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { workflowT } = useI18n();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
content: workflowT('code.Reset template confirm')
|
||||
});
|
||||
|
||||
const CustomComponent = useMemo(
|
||||
() => ({
|
||||
[NodeInputKeyEnum.code]: (item: FlowNodeInputItemType) => {
|
||||
return (
|
||||
<Box>
|
||||
<Flex mb={1} alignItems={'flex-end'}>
|
||||
<Box flex={'1'}>{workflowT('Code')}</Box>
|
||||
<Box
|
||||
cursor={'pointer'}
|
||||
color={'primary.500'}
|
||||
fontSize={'xs'}
|
||||
onClick={openConfirm(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: JS_TEMPLATE
|
||||
}
|
||||
});
|
||||
})}
|
||||
>
|
||||
{workflowT('code.Reset template')}
|
||||
</Box>
|
||||
</Flex>
|
||||
<CodeEditor
|
||||
bg={'white'}
|
||||
borderRadius={'sm'}
|
||||
value={item.value}
|
||||
onChange={(e) => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}),
|
||||
[nodeId, onChangeNode, openConfirm, workflowT]
|
||||
);
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} selected={selected} {...data}>
|
||||
{toolInputs.length > 0 && (
|
||||
<>
|
||||
<Container>
|
||||
<IOTitle text={t('core.module.tool.Tool input')} />
|
||||
<RenderToolInput nodeId={nodeId} inputs={toolInputs} />
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
<Container>
|
||||
<IOTitle text={t('common.Input')} />
|
||||
<RenderInput
|
||||
nodeId={nodeId}
|
||||
flowInputList={commonInputs}
|
||||
CustomComponent={CustomComponent}
|
||||
/>
|
||||
</Container>
|
||||
<Container>
|
||||
<IOTitle text={t('common.Output')} />
|
||||
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
<ConfirmModal />
|
||||
</NodeCard>
|
||||
);
|
||||
};
|
||||
export default React.memo(NodeCode);
|
@@ -72,7 +72,6 @@ const AddInputParam = (props: RenderInputProps) => {
|
||||
leftIcon={<SmallAddIcon />}
|
||||
iconSpacing={1}
|
||||
size={'sm'}
|
||||
mr={'-5px'}
|
||||
onClick={() => setEditField(item.dynamicParamDefaultValue ?? {})}
|
||||
>
|
||||
{t('common.Add New')}
|
||||
|
@@ -13,6 +13,7 @@ import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
|
||||
const RenderList: {
|
||||
types: `${FlowNodeOutputTypeEnum}`[];
|
||||
@@ -61,6 +62,7 @@ const RenderOutput = ({
|
||||
<Box position={'relative'} fontWeight={'medium'}>
|
||||
{t('core.workflow.Custom outputs')}
|
||||
</Box>
|
||||
<QuestionTip ml={1} label={addOutput.description} />
|
||||
<Box flex={'1 0 0'} />
|
||||
<Button
|
||||
variant={'whitePrimary'}
|
||||
|
@@ -148,7 +148,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
if ((await targetCol.countDocuments()) > 1) {
|
||||
// 除了root
|
||||
console.log('team_members 中有数据,无法自动将 buffer.tts 迁移到 team_members,请手动操作');
|
||||
console.log('team_members 中有数据,无法自动将 team.tts 迁移到 team_members,请手动操作');
|
||||
} else {
|
||||
await sourceCol.rename('team_members', { dropTarget: true });
|
||||
console.log('success rename team.members -> team_members');
|
||||
|
Reference in New Issue
Block a user