mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 12:20:34 +00:00
perf: v4.4.6-1 (#364)
This commit is contained in:
@@ -105,6 +105,7 @@
|
||||
},
|
||||
"common": {
|
||||
"Add": "Add",
|
||||
"Close": "Clow",
|
||||
"Collect": "Collect",
|
||||
"Copy": "Copy",
|
||||
"Copy Successful": "Copy Successful",
|
||||
|
@@ -105,6 +105,7 @@
|
||||
},
|
||||
"common": {
|
||||
"Add": "添加",
|
||||
"Close": "关闭",
|
||||
"Collect": "收藏",
|
||||
"Copy": "复制",
|
||||
"Copy Successful": "复制成功",
|
||||
|
@@ -1171,9 +1171,8 @@ export const useChatBox = () => {
|
||||
const historyDom = document.getElementById('history');
|
||||
if (!historyDom) return;
|
||||
const dom = Array.from(historyDom.children).map((child, i) => {
|
||||
const avatar = `<img src="${
|
||||
child.querySelector<HTMLImageElement>('.avatar')?.src
|
||||
}" alt="" />`;
|
||||
const avatar = `<img src="${child.querySelector<HTMLImageElement>('.avatar')
|
||||
?.src}" alt="" />`;
|
||||
|
||||
const chatContent = child.querySelector<HTMLDivElement>('.markdown');
|
||||
|
||||
|
@@ -19,8 +19,8 @@ function MyLink(e: any) {
|
||||
{text}
|
||||
</Link>
|
||||
) : (
|
||||
<Box as={'ul'}>
|
||||
<Box as={'li'}>
|
||||
<Box as={'ul'} mt={'0 !important'}>
|
||||
<Box as={'li'} mb={1}>
|
||||
<Box
|
||||
as={'span'}
|
||||
color={'blue.600'}
|
||||
@@ -47,6 +47,7 @@ const Guide = ({ text }: { text: string }) => {
|
||||
rehypePlugins={[RehypeKatex]}
|
||||
components={{
|
||||
a: MyLink,
|
||||
p: 'div',
|
||||
img: Image
|
||||
}}
|
||||
>
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
FlowValueTypeEnum
|
||||
} from './index';
|
||||
import type { AppItemType } from '@/types/app';
|
||||
import type { FlowModuleTemplateType } from '@/types/flow';
|
||||
import type { FlowModuleTemplateType } from '@/types/core/app/flow';
|
||||
import { chatModelList } from '@/store/static';
|
||||
import {
|
||||
Input_Template_History,
|
||||
@@ -331,6 +331,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
|
||||
'根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于 laf 通用问题\n类型3: 关于 laf 代码问题\n类型4: 其他问题',
|
||||
showStatus: true,
|
||||
inputs: [
|
||||
Input_Template_TFSwitch,
|
||||
{
|
||||
key: 'systemPrompt',
|
||||
type: FlowInputItemTypeEnum.textarea,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { FlowInputItemType } from '@/types/flow';
|
||||
import type { FlowInputItemType } from '@/types/core/app/flow';
|
||||
import { SystemInputEnum } from '../app';
|
||||
import { FlowInputItemTypeEnum, FlowValueTypeEnum } from './index';
|
||||
|
||||
|
@@ -94,9 +94,7 @@ function App({ Component, pageProps }: AppProps) {
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
{scripts?.map((item, i) => (
|
||||
<Script key={i} strategy="lazyOnload" {...item}></Script>
|
||||
))}
|
||||
{scripts?.map((item, i) => <Script key={i} strategy="lazyOnload" {...item}></Script>)}
|
||||
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ChakraProvider theme={theme}>
|
||||
|
@@ -38,8 +38,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
select id, q, a, source, file_id, (vector <#> '[${
|
||||
vectors[0]
|
||||
}]') * -1 AS score from ${PgDatasetTableName} where kb_id='${kbId}' AND user_id='${userId}' order by vector <#> '[${
|
||||
vectors[0]
|
||||
}]' limit 12;
|
||||
vectors[0]
|
||||
}]' limit 12;
|
||||
COMMIT;`
|
||||
);
|
||||
|
||||
|
@@ -32,7 +32,7 @@ import { getSystemTime } from '@/utils/user';
|
||||
import { authOutLinkChat } from '@/service/support/outLink/auth';
|
||||
import requestIp from 'request-ip';
|
||||
import { replaceVariable } from '@/utils/common/tools/text';
|
||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
import { selectShareResponse } from '@/utils/service/core/chat';
|
||||
import { pushResult2Remote, updateOutLinkUsage } from '@/service/support/outLink';
|
||||
import { updateApiKeyUsage } from '@/service/support/openapi';
|
||||
|
@@ -1,20 +1,15 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { AppModuleItemType } from '@/types/app';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useFlowStore } from './Provider';
|
||||
|
||||
const ImportSettings = ({
|
||||
onClose,
|
||||
onSuccess
|
||||
}: {
|
||||
onClose: () => void;
|
||||
onSuccess: (modules: AppModuleItemType[]) => void;
|
||||
}) => {
|
||||
const ImportSettings = ({ onClose }: { onClose: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const [value, setValue] = useState('');
|
||||
const { setNodes, setEdges, initData } = useFlowStore();
|
||||
|
||||
return (
|
||||
<MyModal isOpen w={'600px'} onClose={onClose} title={t('app.Import Config')}>
|
||||
@@ -35,7 +30,11 @@ const ImportSettings = ({
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(value);
|
||||
onSuccess(data);
|
||||
setEdges([]);
|
||||
setNodes([]);
|
||||
setTimeout(() => {
|
||||
initData(data);
|
||||
}, 10);
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast({
|
||||
@@ -51,4 +50,4 @@ const ImportSettings = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default ImportSettings;
|
||||
export default React.memo(ImportSettings);
|
||||
|
@@ -1,18 +1,18 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
|
||||
const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs, onChangeNode } = data;
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
return (
|
||||
<NodeCard minW={'400px'} {...data}>
|
||||
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
|
||||
<RenderInput moduleId={moduleId} onChangeNode={onChangeNode} flowInputList={inputs} />
|
||||
<RenderOutput onChangeNode={onChangeNode} moduleId={moduleId} flowOutputList={outputs} />
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { Box, Input, Button, Flex } from '@chakra-ui/react';
|
||||
import { Box, Input, Button, Flex, Textarea } from '@chakra-ui/react';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
@@ -11,17 +11,22 @@ import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 4);
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { FlowOutputItemTypeEnum, FlowValueTypeEnum, SpecialInputKeyEnum } from '@/constants/flow';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import SourceHandle from '../render/SourceHandle';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs, onChangeNode } = data;
|
||||
const { t } = useTranslation();
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} {...data}>
|
||||
<Divider text="Input" />
|
||||
<Container>
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
onChangeNode={onChangeNode}
|
||||
flowInputList={inputs}
|
||||
CustomComponent={{
|
||||
[SpecialInputKeyEnum.agents]: ({
|
||||
@@ -34,51 +39,23 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
}) => (
|
||||
<Box>
|
||||
{agents.map((item, i) => (
|
||||
<Flex key={item.key} mb={4} alignItems={'center'}>
|
||||
<MyIcon
|
||||
mr={2}
|
||||
name={'minus'}
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
color={'myGray.600'}
|
||||
_hover={{ color: 'myGray.900' }}
|
||||
onClick={() => {
|
||||
const newInputValue = agents.filter((input) => input.key !== item.key);
|
||||
const newOutputVal = outputs.filter((output) => output.key !== item.key);
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: agentKey,
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: newInputValue
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: newOutputVal
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Box flex={1}>
|
||||
<Box flex={1}>类型{i + 1}</Box>
|
||||
<Box position={'relative'}>
|
||||
<Input
|
||||
<Box key={item.key} mb={4}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyTooltip label={t('common.Delete')}>
|
||||
<MyIcon
|
||||
mt={1}
|
||||
defaultValue={item.value}
|
||||
onChange={(e) => {
|
||||
const newVal = agents.map((val) =>
|
||||
val.key === item.key
|
||||
? {
|
||||
...val,
|
||||
value: e.target.value
|
||||
}
|
||||
: val
|
||||
mr={2}
|
||||
name={'minus'}
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
color={'myGray.600'}
|
||||
_hover={{ color: 'red.600' }}
|
||||
onClick={() => {
|
||||
const newInputValue = agents.filter((input) => input.key !== item.key);
|
||||
const newOutputVal = outputs.filter(
|
||||
(output) => output.key !== item.key
|
||||
);
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
@@ -86,15 +63,49 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: newVal
|
||||
value: newInputValue
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: newOutputVal
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<SourceHandle handleKey={item.key} valueType={FlowValueTypeEnum.boolean} />
|
||||
</Box>
|
||||
</MyTooltip>
|
||||
<Box flex={1}>分类{i + 1}</Box>
|
||||
</Flex>
|
||||
<Box position={'relative'}>
|
||||
<Textarea
|
||||
rows={2}
|
||||
mt={1}
|
||||
defaultValue={item.value}
|
||||
onChange={(e) => {
|
||||
const newVal = agents.map((val) =>
|
||||
val.key === item.key
|
||||
? {
|
||||
...val,
|
||||
value: e.target.value
|
||||
}
|
||||
: val
|
||||
);
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: agentKey,
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: newVal
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<SourceHandle handleKey={item.key} valueType={FlowValueTypeEnum.boolean} />
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
))}
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
@@ -9,16 +9,18 @@ import RenderOutput from '../render/RenderOutput';
|
||||
import MySelect from '@/components/Select';
|
||||
import { chatModelList } from '@/store/static';
|
||||
import MySlider from '@/components/Slider';
|
||||
import { Box, Button, Flex, useDisclosure } from '@chakra-ui/react';
|
||||
import { Box, Button, useDisclosure } from '@chakra-ui/react';
|
||||
import { formatPrice } from '@fastgpt/common/bill/index';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { AIChatProps } from '@/types/core/aiChat';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const AIChatSettingsModal = dynamic(() => import('../../../AIChatSettingsModal'));
|
||||
|
||||
const NodeChat = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs, onChangeNode } = data;
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
const chatModulesData = useMemo(() => {
|
||||
const obj: Record<string, any> = {};
|
||||
@@ -40,7 +42,6 @@ const NodeChat = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
<Container>
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
onChangeNode={onChangeNode}
|
||||
flowInputList={inputs}
|
||||
CustomComponent={{
|
||||
model: (inputItem) => {
|
||||
@@ -140,7 +141,7 @@ const NodeChat = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput onChangeNode={onChangeNode} moduleId={moduleId} flowOutputList={outputs} />
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
|
||||
{isOpenAIChatSetting && (
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
|
||||
const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
return <NodeCard {...data}></NodeCard>;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import Container from '../modules/Container';
|
||||
@@ -14,11 +14,13 @@ import MyIcon from '@/components/Icon';
|
||||
import ExtractFieldModal from '../modules/ExtractFieldModal';
|
||||
import { ContextExtractEnum } from '@/constants/flow/flowField';
|
||||
import { FlowOutputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { inputs, outputs, moduleId, onChangeNode, onDelEdge } = data;
|
||||
const { inputs, outputs, moduleId } = data;
|
||||
const { t } = useTranslation();
|
||||
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
|
||||
const { onChangeNode, onDelEdge } = useFlowStore();
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} {...data}>
|
||||
@@ -26,7 +28,6 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
<Container>
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
onChangeNode={onChangeNode}
|
||||
flowInputList={inputs}
|
||||
CustomComponent={{
|
||||
[ContextExtractEnum.extractKeys]: ({
|
||||
@@ -125,7 +126,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput onChangeNode={onChangeNode} moduleId={moduleId} flowOutputList={outputs} />
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
|
||||
{!!editExtractFiled && (
|
||||
|
@@ -1,23 +1,23 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
|
||||
const NodeHistory = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { inputs, outputs, moduleId, onChangeNode } = data;
|
||||
const { inputs, outputs, moduleId } = data;
|
||||
return (
|
||||
<NodeCard minW={'300px'} {...data}>
|
||||
<Divider text="Input" />
|
||||
<Container>
|
||||
<RenderInput moduleId={moduleId} onChangeNode={onChangeNode} flowInputList={inputs} />
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput onChangeNode={onChangeNode} moduleId={moduleId} flowOutputList={outputs} />
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
@@ -12,13 +12,16 @@ import RenderOutput from '../render/RenderOutput';
|
||||
import { FlowInputItemTypeEnum, FlowOutputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs, onChangeNode } = data;
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<NodeCard minW={'350px'} {...data}>
|
||||
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
|
||||
<RenderInput moduleId={moduleId} onChangeNode={onChangeNode} flowInputList={inputs} />
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
<Button
|
||||
variant={'base'}
|
||||
mt={5}
|
||||
@@ -44,7 +47,7 @@ const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput onChangeNode={onChangeNode} moduleId={moduleId} flowOutputList={outputs} />
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
<Box textAlign={'right'} mt={5}>
|
||||
<Button
|
||||
variant={'base'}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import { Flex, Box, Button, useTheme, useDisclosure, Grid } from '@chakra-ui/react';
|
||||
import { useDatasetStore } from '@/store/dataset';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
@@ -12,6 +12,7 @@ import RenderOutput from '../render/RenderOutput';
|
||||
import { DatasetSelectModal } from '../../../DatasetSelectModal';
|
||||
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const KBSelect = ({
|
||||
activeKbs = [],
|
||||
@@ -68,14 +69,15 @@ const KBSelect = ({
|
||||
};
|
||||
|
||||
const NodeKbSearch = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs, onChangeNode } = data;
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} {...data}>
|
||||
<Divider text="Input" />
|
||||
<Container>
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
onChangeNode={onChangeNode}
|
||||
flowInputList={inputs}
|
||||
CustomComponent={{
|
||||
kbList: ({ key, value, ...props }) => (
|
||||
@@ -100,7 +102,7 @@ const NodeKbSearch = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput onChangeNode={onChangeNode} moduleId={moduleId} flowOutputList={outputs} />
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
|
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Container from '../modules/Container';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { FlowValueTypeEnum } from '@/constants/flow';
|
||||
|
@@ -3,7 +3,7 @@ import { Handle, Position, NodeProps } from 'reactflow';
|
||||
import { Flex, Box } from '@chakra-ui/react';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import Label from '../modules/Label';
|
||||
|
@@ -15,9 +15,10 @@ import {
|
||||
Switch
|
||||
} from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { welcomeTextTip, variableTip, questionGuideTip } from '@/constants/flow/ModuleTemplate';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
import VariableEditModal, { addVariable } from '../../../VariableEditModal';
|
||||
import MyIcon from '@/components/Icon';
|
||||
@@ -47,7 +48,8 @@ const NodeUserGuide = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
export default React.memo(NodeUserGuide);
|
||||
|
||||
export function WelcomeText({ data }: { data: FlowModuleItemType }) {
|
||||
const { inputs, moduleId, onChangeNode } = data;
|
||||
const { inputs, moduleId } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
const welcomeText = useMemo(
|
||||
() => inputs.find((item) => item.key === SystemInputEnum.welcomeText),
|
||||
@@ -89,7 +91,9 @@ export function WelcomeText({ data }: { data: FlowModuleItemType }) {
|
||||
}
|
||||
|
||||
function ChatStartVariable({ data }: { data: FlowModuleItemType }) {
|
||||
const { inputs, moduleId, onChangeNode } = data;
|
||||
const { inputs, moduleId } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
const variables = useMemo(
|
||||
() =>
|
||||
(inputs.find((item) => item.key === SystemInputEnum.variables)
|
||||
@@ -203,7 +207,9 @@ function ChatStartVariable({ data }: { data: FlowModuleItemType }) {
|
||||
}
|
||||
|
||||
function QuestionGuide({ data }: { data: FlowModuleItemType }) {
|
||||
const { inputs, moduleId, onChangeNode } = data;
|
||||
const { inputs, moduleId } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
const questionGuide = useMemo(
|
||||
() =>
|
||||
(inputs.find((item) => item.key === SystemInputEnum.questionGuide)?.value as boolean) ||
|
||||
|
@@ -1,9 +1,10 @@
|
||||
/* Abandon */
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Container from '../modules/Container';
|
||||
import { SystemInputEnum, VariableInputEnum } from '@/constants/app';
|
||||
import type { VariableItemType } from '@/types/app';
|
||||
@@ -11,6 +12,7 @@ import MyIcon from '@/components/Icon';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
import VariableEditModal, { addVariable } from '../../../VariableEditModal';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
export const defaultVariable: VariableItemType = {
|
||||
id: nanoid(),
|
||||
@@ -23,7 +25,9 @@ export const defaultVariable: VariableItemType = {
|
||||
};
|
||||
|
||||
const NodeUserGuide = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { inputs, moduleId, onChangeNode } = data;
|
||||
const { inputs, moduleId } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
const variables = useMemo(
|
||||
() =>
|
||||
(inputs.find((item) => item.key === SystemInputEnum.variables)
|
||||
|
@@ -0,0 +1,352 @@
|
||||
import {
|
||||
type Node,
|
||||
type NodeChange,
|
||||
type Edge,
|
||||
type EdgeChange,
|
||||
useNodesState,
|
||||
useEdgesState,
|
||||
XYPosition,
|
||||
useViewport,
|
||||
Connection,
|
||||
addEdge
|
||||
} from 'reactflow';
|
||||
import type {
|
||||
FlowModuleItemType,
|
||||
FlowModuleTemplateType,
|
||||
FlowOutputTargetItemType,
|
||||
FlowModuleItemChangeProps
|
||||
} from '@/types/core/app/flow';
|
||||
import React, {
|
||||
type SetStateAction,
|
||||
type Dispatch,
|
||||
useContext,
|
||||
useCallback,
|
||||
createContext,
|
||||
useRef
|
||||
} from 'react';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { FlowModuleTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { AppModuleItemType } from '@/types/app';
|
||||
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
|
||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||
export type useFlowStoreType = {
|
||||
reactFlowWrapper: null | React.RefObject<HTMLDivElement>;
|
||||
nodes: Node<FlowModuleItemType, string | undefined>[];
|
||||
setNodes: Dispatch<SetStateAction<Node<FlowModuleItemType, string | undefined>[]>>;
|
||||
onNodesChange: OnChange<NodeChange>;
|
||||
edges: Edge<any>[];
|
||||
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
||||
onEdgesChange: OnChange<EdgeChange>;
|
||||
onFixView: () => void;
|
||||
onAddNode: (e: { template: FlowModuleTemplateType; position: XYPosition }) => void;
|
||||
onDelNode: (nodeId: string) => void;
|
||||
onChangeNode: (e: FlowModuleItemChangeProps) => void;
|
||||
onCopyNode: (nodeId: string) => void;
|
||||
onDelEdge: (e: {
|
||||
moduleId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}) => void;
|
||||
onDelConnect: (id: string) => void;
|
||||
onConnect: ({ connect }: { connect: Connection }) => any;
|
||||
initData: (modules: AppModuleItemType[]) => void;
|
||||
};
|
||||
|
||||
const StateContext = createContext<useFlowStoreType>({
|
||||
reactFlowWrapper: null,
|
||||
nodes: [],
|
||||
setNodes: function (
|
||||
value: React.SetStateAction<Node<FlowModuleItemType, string | undefined>[]>
|
||||
): void {
|
||||
return;
|
||||
},
|
||||
onNodesChange: function (changes: NodeChange[]): void {
|
||||
return;
|
||||
},
|
||||
edges: [],
|
||||
setEdges: function (value: React.SetStateAction<Edge<any>[]>): void {
|
||||
return;
|
||||
},
|
||||
onEdgesChange: function (changes: EdgeChange[]): void {
|
||||
return;
|
||||
},
|
||||
onFixView: function (): void {
|
||||
return;
|
||||
},
|
||||
onAddNode: function (e: { template: FlowModuleTemplateType; position: XYPosition }): void {
|
||||
return;
|
||||
},
|
||||
onDelNode: function (nodeId: string): void {
|
||||
return;
|
||||
},
|
||||
onChangeNode: function (e: FlowModuleItemChangeProps): void {
|
||||
return;
|
||||
},
|
||||
onCopyNode: function (nodeId: string): void {
|
||||
return;
|
||||
},
|
||||
onDelEdge: function (e: {
|
||||
moduleId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}): void {
|
||||
return;
|
||||
},
|
||||
onDelConnect: function (id: string): void {
|
||||
return;
|
||||
},
|
||||
onConnect: function ({ connect }: { connect: Connection }) {
|
||||
return;
|
||||
},
|
||||
initData: function (modules: AppModuleItemType[]): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}
|
||||
});
|
||||
export const useFlowStore = () => useContext(StateContext);
|
||||
|
||||
export const FlowProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowModuleItemType>([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const { x, y, zoom } = useViewport();
|
||||
|
||||
const onFixView = useCallback(() => {
|
||||
const btn = document.querySelector('.react-flow__controls-fitview') as HTMLButtonElement;
|
||||
|
||||
setTimeout(() => {
|
||||
btn && btn.click();
|
||||
}, 100);
|
||||
}, []);
|
||||
|
||||
const onDelEdge = useCallback(
|
||||
({
|
||||
moduleId,
|
||||
sourceHandle,
|
||||
targetHandle
|
||||
}: {
|
||||
moduleId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}) => {
|
||||
if (!sourceHandle && !targetHandle) return;
|
||||
setEdges((state) =>
|
||||
state.filter((edge) => {
|
||||
if (edge.source === moduleId && edge.sourceHandle === sourceHandle) return false;
|
||||
if (edge.target === moduleId && edge.targetHandle === targetHandle) return false;
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
},
|
||||
[setEdges]
|
||||
);
|
||||
|
||||
const onDelConnect = useCallback(
|
||||
(id: string) => {
|
||||
setEdges((state) => state.filter((item) => item.id !== id));
|
||||
},
|
||||
[setEdges]
|
||||
);
|
||||
|
||||
const onConnect = useCallback(
|
||||
({ connect }: { connect: Connection }) => {
|
||||
const source = nodes.find((node) => node.id === connect.source)?.data;
|
||||
const sourceType = (() => {
|
||||
if (source?.flowType === FlowModuleTypeEnum.classifyQuestion) {
|
||||
return FlowValueTypeEnum.boolean;
|
||||
}
|
||||
return source?.outputs.find((output) => output.key === connect.sourceHandle)?.valueType;
|
||||
})();
|
||||
|
||||
const targetType = nodes
|
||||
.find((node) => node.id === connect.target)
|
||||
?.data?.inputs.find((input) => input.key === connect.targetHandle)?.valueType;
|
||||
|
||||
if (!sourceType || !targetType) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('app.Connection is invalid')
|
||||
});
|
||||
}
|
||||
if (
|
||||
sourceType !== FlowValueTypeEnum.any &&
|
||||
targetType !== FlowValueTypeEnum.any &&
|
||||
sourceType !== targetType
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('app.Connection type is different')
|
||||
});
|
||||
}
|
||||
|
||||
setEdges((state) =>
|
||||
addEdge(
|
||||
{
|
||||
...connect,
|
||||
type: 'buttonedge',
|
||||
animated: true,
|
||||
data: {
|
||||
onDelete: onDelConnect
|
||||
}
|
||||
},
|
||||
state
|
||||
)
|
||||
);
|
||||
},
|
||||
[nodes, onDelConnect, setEdges, t, toast]
|
||||
);
|
||||
|
||||
const onAddNode = useCallback(
|
||||
({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => {
|
||||
if (!reactFlowWrapper.current) return;
|
||||
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100;
|
||||
const mouseY = (position.y - reactFlowBounds.top - y) / zoom;
|
||||
console.log(template);
|
||||
setNodes((state) =>
|
||||
state.concat(
|
||||
appModule2FlowNode({
|
||||
item: {
|
||||
...template,
|
||||
moduleId: nanoid(),
|
||||
position: { x: mouseX, y: mouseY }
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
[setNodes, x, y, zoom]
|
||||
);
|
||||
|
||||
const onDelNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
setNodes((state) => state.filter((item) => item.id !== nodeId));
|
||||
setEdges((state) => state.filter((edge) => edge.source !== nodeId && edge.target !== nodeId));
|
||||
},
|
||||
[setEdges, setNodes]
|
||||
);
|
||||
|
||||
const onChangeNode = useCallback(
|
||||
({ moduleId, key, type = 'inputs', value }: FlowModuleItemChangeProps) => {
|
||||
setNodes((nodes) =>
|
||||
nodes.map((node) => {
|
||||
if (node.id !== moduleId) return node;
|
||||
|
||||
const updateObj: Record<string, any> = {};
|
||||
|
||||
if (type === 'inputs') {
|
||||
updateObj.inputs = node.data.inputs.map((item) => (item.key === key ? value : item));
|
||||
} else if (type === 'addInput') {
|
||||
const input = node.data.inputs.find((input) => input.key === value.key);
|
||||
if (input) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: 'key 重复'
|
||||
});
|
||||
updateObj.inputs = node.data.inputs;
|
||||
} else {
|
||||
updateObj.inputs = node.data.inputs.concat(value);
|
||||
}
|
||||
} else if (type === 'delInput') {
|
||||
onDelEdge({ moduleId, targetHandle: key });
|
||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== key);
|
||||
} else if (type === 'attr') {
|
||||
updateObj[key] = value;
|
||||
} else if (type === 'outputs') {
|
||||
// del output connect
|
||||
const delOutputs = node.data.outputs.filter(
|
||||
(item) => !value.find((output: FlowOutputTargetItemType) => output.key === item.key)
|
||||
);
|
||||
delOutputs.forEach((output) => {
|
||||
onDelEdge({ moduleId, sourceHandle: output.key });
|
||||
});
|
||||
updateObj.outputs = value;
|
||||
}
|
||||
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
...updateObj
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
[onDelEdge, setNodes, toast]
|
||||
);
|
||||
|
||||
const onCopyNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
setNodes((nodes) => {
|
||||
const node = nodes.find((node) => node.id === nodeId);
|
||||
if (!node) return nodes;
|
||||
const template = {
|
||||
logo: node.data.logo,
|
||||
name: node.data.name,
|
||||
intro: node.data.intro,
|
||||
description: node.data.description,
|
||||
flowType: node.data.flowType,
|
||||
inputs: node.data.inputs,
|
||||
outputs: node.data.outputs,
|
||||
showStatus: node.data.showStatus
|
||||
};
|
||||
return nodes.concat(
|
||||
appModule2FlowNode({
|
||||
item: {
|
||||
...template,
|
||||
moduleId: nanoid(),
|
||||
position: { x: node.position.x + 200, y: node.position.y + 50 }
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
[setNodes]
|
||||
);
|
||||
|
||||
const initData = useCallback(
|
||||
(modules: AppModuleItemType[]) => {
|
||||
const edges = appModule2FlowEdge({
|
||||
modules,
|
||||
onDelete: onDelConnect
|
||||
});
|
||||
setEdges(edges);
|
||||
|
||||
setNodes(modules.map((item) => appModule2FlowNode({ item })));
|
||||
|
||||
onFixView();
|
||||
},
|
||||
[onDelConnect, setEdges, setNodes, onFixView]
|
||||
);
|
||||
|
||||
const value = {
|
||||
reactFlowWrapper,
|
||||
nodes,
|
||||
setNodes,
|
||||
onNodesChange,
|
||||
edges,
|
||||
setEdges,
|
||||
onEdgesChange,
|
||||
onFixView,
|
||||
onAddNode,
|
||||
onDelNode,
|
||||
onChangeNode,
|
||||
onCopyNode,
|
||||
onDelEdge,
|
||||
onDelConnect,
|
||||
onConnect,
|
||||
initData
|
||||
};
|
||||
|
||||
return <StateContext.Provider value={value}>{children}</StateContext.Provider>;
|
||||
};
|
||||
|
||||
export default React.memo(FlowProvider);
|
@@ -1,23 +1,23 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { ModuleTemplates } from '@/constants/flow/ModuleTemplate';
|
||||
import { FlowModuleItemType, FlowModuleTemplateType } from '@/types/flow';
|
||||
import type { Node, XYPosition } from 'reactflow';
|
||||
import { FlowModuleItemType, FlowModuleTemplateType } from '@/types/core/app/flow';
|
||||
import type { Node } from 'reactflow';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { useFlowStore } from './Provider';
|
||||
|
||||
const ModuleTemplateList = ({
|
||||
nodes,
|
||||
isOpen,
|
||||
onAddNode,
|
||||
onClose
|
||||
}: {
|
||||
nodes?: Node<FlowModuleItemType>[];
|
||||
isOpen: boolean;
|
||||
onAddNode: (e: { template: FlowModuleTemplateType; position: XYPosition }) => void;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { onAddNode } = useFlowStore();
|
||||
const { isPc } = useGlobalStore();
|
||||
|
||||
const filterTemplates = useMemo(() => {
|
||||
@@ -123,4 +123,4 @@ const ModuleTemplateList = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default ModuleTemplateList;
|
||||
export default React.memo(ModuleTemplateList);
|
||||
|
@@ -7,8 +7,7 @@ import {
|
||||
ModalBody,
|
||||
Flex,
|
||||
Switch,
|
||||
Input,
|
||||
FormControl
|
||||
Input
|
||||
} from '@chakra-ui/react';
|
||||
import type { ContextExtractAgentItemType } from '@/types/app';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
@@ -2,12 +2,13 @@ import React, { useMemo } from 'react';
|
||||
import { Box, Flex, useTheme, Menu, MenuButton, MenuList, MenuItem } from '@chakra-ui/react';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import type { FlowModuleItemType } from '@/types/flow';
|
||||
import type { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useEditTitle } from '@/hooks/useEditTitle';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
type Props = FlowModuleItemType & {
|
||||
children?: React.ReactNode | React.ReactNode[] | string;
|
||||
@@ -21,11 +22,10 @@ const NodeCard = (props: Props) => {
|
||||
name = '未知模块',
|
||||
description,
|
||||
minW = '300px',
|
||||
onCopyNode,
|
||||
onDelNode,
|
||||
onChangeNode,
|
||||
|
||||
moduleId
|
||||
} = props;
|
||||
const { onCopyNode, onDelNode, onChangeNode } = useFlowStore();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
@@ -73,11 +73,11 @@ const NodeCard = (props: Props) => {
|
||||
|
||||
{
|
||||
icon: 'back',
|
||||
label: t('Cancel'),
|
||||
label: t('common.Close'),
|
||||
onClick: () => {}
|
||||
}
|
||||
],
|
||||
[moduleId, onCopyNode, onDelNode, t]
|
||||
[moduleId, name, onChangeNode, onCopyNode, onDelNode, onOpenModal, t, toast]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -92,6 +92,7 @@ const NodeCard = (props: Props) => {
|
||||
<QuestionOutlineIcon
|
||||
display={['none', 'inline']}
|
||||
transform={'translateY(1px)'}
|
||||
mb={'1px'}
|
||||
ml={1}
|
||||
/>
|
||||
</MyTooltip>
|
||||
|
@@ -19,7 +19,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { FlowInputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import MySelect from '@/components/Select';
|
||||
import { FlowInputItemType } from '@/types/flow';
|
||||
import type { FlowInputItemType } from '@/types/core/app/flow';
|
||||
|
||||
const typeSelectList = [
|
||||
{
|
||||
|
@@ -1,16 +1,5 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ModalHeader,
|
||||
ModalFooter,
|
||||
ModalBody,
|
||||
Flex,
|
||||
Switch,
|
||||
Input,
|
||||
FormControl
|
||||
} from '@chakra-ui/react';
|
||||
import type { ContextExtractAgentItemType, HttpFieldItemType } from '@/types/app';
|
||||
import { Box, Button, ModalHeader, ModalFooter, ModalBody, Flex, Input } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
@@ -20,7 +9,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { FlowOutputItemTypeEnum, FlowValueTypeEnum, FlowValueTypeStyle } from '@/constants/flow';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import MySelect from '@/components/Select';
|
||||
import { FlowOutputItemType } from '@/types/flow';
|
||||
import { FlowOutputItemType } from '@/types/core/app/flow';
|
||||
|
||||
const typeSelectList = [
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import type { FlowInputItemType, FlowModuleItemType } from '@/types/flow';
|
||||
import type { FlowInputItemType } from '@/types/core/app/flow';
|
||||
import {
|
||||
Box,
|
||||
Textarea,
|
||||
@@ -20,19 +20,19 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import TargetHandle from './TargetHandle';
|
||||
import MyIcon from '@/components/Icon';
|
||||
const SetInputFieldModal = dynamic(() => import('../modules/SetInputFieldModal'));
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
export const Label = ({
|
||||
moduleId,
|
||||
inputKey,
|
||||
onChangeNode,
|
||||
...item
|
||||
}: FlowInputItemType & {
|
||||
moduleId: string;
|
||||
inputKey: string;
|
||||
onChangeNode: FlowModuleItemType['onChangeNode'];
|
||||
}) => {
|
||||
const { required = false, description, edit, label, type, valueType } = item;
|
||||
const [editField, setEditField] = useState<FlowInputItemType>();
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<Flex className="nodrag" cursor={'default'} alignItems={'center'} position={'relative'}>
|
||||
@@ -134,28 +134,20 @@ export const Label = ({
|
||||
const RenderInput = ({
|
||||
flowInputList,
|
||||
moduleId,
|
||||
CustomComponent = {},
|
||||
onChangeNode
|
||||
CustomComponent = {}
|
||||
}: {
|
||||
flowInputList: FlowInputItemType[];
|
||||
moduleId: string;
|
||||
CustomComponent?: Record<string, (e: FlowInputItemType) => React.ReactNode>;
|
||||
onChangeNode: FlowModuleItemType['onChangeNode'];
|
||||
}) => {
|
||||
const { onChangeNode } = useFlowStore();
|
||||
return (
|
||||
<>
|
||||
{flowInputList.map(
|
||||
(item) =>
|
||||
item.type !== FlowInputItemTypeEnum.hidden && (
|
||||
<Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}>
|
||||
{!!item.label && (
|
||||
<Label
|
||||
moduleId={moduleId}
|
||||
onChangeNode={onChangeNode}
|
||||
inputKey={item.key}
|
||||
{...item}
|
||||
/>
|
||||
)}
|
||||
{!!item.label && <Label moduleId={moduleId} inputKey={item.key} {...item} />}
|
||||
<Box mt={2} className={'nodrag'}>
|
||||
{item.type === FlowInputItemTypeEnum.numberInput && (
|
||||
<NumberInput
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import type { FlowModuleItemType, FlowOutputItemType } from '@/types/flow';
|
||||
import type { FlowOutputItemType } from '@/types/core/app/flow';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { FlowOutputItemTypeEnum } from '@/constants/flow';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
@@ -8,21 +8,21 @@ import SourceHandle from './SourceHandle';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import dynamic from 'next/dynamic';
|
||||
const SetOutputFieldModal = dynamic(() => import('../modules/SetOutputFieldModal'));
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const Label = ({
|
||||
moduleId,
|
||||
outputKey,
|
||||
outputs,
|
||||
onChangeNode,
|
||||
...item
|
||||
}: FlowOutputItemType & {
|
||||
outputKey: string;
|
||||
moduleId: string;
|
||||
outputs: FlowOutputItemType[];
|
||||
onChangeNode: FlowModuleItemType['onChangeNode'];
|
||||
}) => {
|
||||
const { label, description, edit } = item;
|
||||
const [editField, setEditField] = useState<FlowOutputItemType>();
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<Flex
|
||||
@@ -122,12 +122,10 @@ const Label = ({
|
||||
|
||||
const RenderOutput = ({
|
||||
moduleId,
|
||||
flowOutputList,
|
||||
onChangeNode
|
||||
flowOutputList
|
||||
}: {
|
||||
moduleId: string;
|
||||
flowOutputList: FlowOutputItemType[];
|
||||
onChangeNode: FlowModuleItemType['onChangeNode'];
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
@@ -135,13 +133,7 @@ const RenderOutput = ({
|
||||
(item) =>
|
||||
item.type !== FlowOutputItemTypeEnum.hidden && (
|
||||
<Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}>
|
||||
<Label
|
||||
moduleId={moduleId}
|
||||
onChangeNode={onChangeNode}
|
||||
outputKey={item.key}
|
||||
outputs={flowOutputList}
|
||||
{...item}
|
||||
/>
|
||||
<Label moduleId={moduleId} outputKey={item.key} outputs={flowOutputList} {...item} />
|
||||
<Box mt={FlowOutputItemTypeEnum.answer ? 0 : 2} className={'nodrag'}>
|
||||
{item.type === FlowOutputItemTypeEnum.source && (
|
||||
<SourceHandle handleKey={item.key} valueType={item.valueType} />
|
||||
|
@@ -1,89 +1,45 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
Controls,
|
||||
ReactFlowProvider,
|
||||
addEdge,
|
||||
useNodesState,
|
||||
useEdgesState,
|
||||
XYPosition,
|
||||
Connection,
|
||||
useViewport
|
||||
} from 'reactflow';
|
||||
import ReactFlow, { Background, Controls, ReactFlowProvider } from 'reactflow';
|
||||
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
|
||||
import { SmallCloseIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
edgeOptions,
|
||||
connectionLineStyle,
|
||||
FlowModuleTypeEnum,
|
||||
FlowInputItemTypeEnum,
|
||||
FlowValueTypeEnum
|
||||
FlowInputItemTypeEnum
|
||||
} from '@/constants/flow';
|
||||
import { appModule2FlowNode, appModule2FlowEdge } from '@/utils/adapt';
|
||||
import {
|
||||
FlowModuleItemType,
|
||||
FlowModuleTemplateType,
|
||||
FlowOutputTargetItemType,
|
||||
type FlowModuleItemChangeProps
|
||||
} from '@/types/flow';
|
||||
import { FlowOutputTargetItemType } from '@/types/core/app/flow';
|
||||
import { AppModuleItemType } from '@/types/app';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { useRequest } from '@/hooks/useRequest';
|
||||
import type { AppSchema } from '@/types/mongoSchema';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useCopyData } from '@/hooks/useCopyData';
|
||||
import dynamic from 'next/dynamic';
|
||||
import styles from './index.module.scss';
|
||||
import { AppTypeEnum } from '@/constants/app';
|
||||
|
||||
import MyIcon from '@/components/Icon';
|
||||
import ButtonEdge from './components/modules/ButtonEdge';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import TemplateList from './components/TemplateList';
|
||||
import ChatTest, { type ChatTestComponentRef } from './components/ChatTest';
|
||||
import FlowProvider, { useFlowStore } from './components/Provider';
|
||||
|
||||
const ImportSettings = dynamic(() => import('./components/ImportSettings'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeChat = dynamic(() => import('./components/Nodes/NodeChat'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeKbSearch = dynamic(() => import('./components/Nodes/NodeKbSearch'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeHistory = dynamic(() => import('./components/Nodes/NodeHistory'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeTFSwitch = dynamic(() => import('./components/Nodes/NodeTFSwitch'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeAnswer = dynamic(() => import('./components/Nodes/NodeAnswer'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeQuestionInput = dynamic(() => import('./components/Nodes/NodeQuestionInput'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeCQNode = dynamic(() => import('./components/Nodes/NodeCQNode'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeVariable = dynamic(() => import('./components/Nodes/NodeVariable'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeUserGuide = dynamic(() => import('./components/Nodes/NodeUserGuide'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeExtract = dynamic(() => import('./components/Nodes/NodeExtract'), {
|
||||
ssr: false
|
||||
});
|
||||
const NodeHttp = dynamic(() => import('./components/Nodes/NodeHttp'), {
|
||||
ssr: false
|
||||
});
|
||||
const ImportSettings = dynamic(() => import('./components/ImportSettings'));
|
||||
const NodeChat = dynamic(() => import('./components/Nodes/NodeChat'));
|
||||
const NodeKbSearch = dynamic(() => import('./components/Nodes/NodeKbSearch'));
|
||||
const NodeHistory = dynamic(() => import('./components/Nodes/NodeHistory'));
|
||||
const NodeTFSwitch = dynamic(() => import('./components/Nodes/NodeTFSwitch'));
|
||||
const NodeAnswer = dynamic(() => import('./components/Nodes/NodeAnswer'));
|
||||
const NodeQuestionInput = dynamic(() => import('./components/Nodes/NodeQuestionInput'));
|
||||
const NodeCQNode = dynamic(() => import('./components/Nodes/NodeCQNode'));
|
||||
const NodeVariable = dynamic(() => import('./components/Nodes/NodeVariable'));
|
||||
const NodeUserGuide = dynamic(() => import('./components/Nodes/NodeUserGuide'));
|
||||
const NodeExtract = dynamic(() => import('./components/Nodes/NodeExtract'));
|
||||
const NodeHttp = dynamic(() => import('./components/Nodes/NodeHttp'));
|
||||
|
||||
import 'reactflow/dist/style.css';
|
||||
import styles from './index.module.scss';
|
||||
import { AppTypeEnum } from '@/constants/app';
|
||||
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
|
||||
const nodeTypes = {
|
||||
[FlowModuleTypeEnum.userGuide]: NodeUserGuide,
|
||||
@@ -104,131 +60,17 @@ const edgeTypes = {
|
||||
};
|
||||
type Props = { app: AppSchema; onCloseSettings: () => void };
|
||||
|
||||
const AppEdit = ({ app, onCloseSettings }: Props) => {
|
||||
function FlowHeader({ app, onCloseSettings }: Props & {}) {
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const { copyData } = useCopyData();
|
||||
|
||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||
const ChatTestRef = useRef<ChatTestComponentRef>(null);
|
||||
|
||||
const { updateAppDetail } = useUserStore();
|
||||
const { x, y, zoom } = useViewport();
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState<FlowModuleItemType>([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const {
|
||||
isOpen: isOpenTemplate,
|
||||
onOpen: onOpenTemplate,
|
||||
onClose: onCloseTemplate
|
||||
} = useDisclosure();
|
||||
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
||||
const { updateAppDetail } = useUserStore();
|
||||
const { nodes, edges, onFixView } = useFlowStore();
|
||||
|
||||
const [testModules, setTestModules] = useState<AppModuleItemType[]>();
|
||||
|
||||
const onFixView = useCallback(() => {
|
||||
const btn = document.querySelector('.react-flow__controls-fitview') as HTMLButtonElement;
|
||||
|
||||
setTimeout(() => {
|
||||
btn && btn.click();
|
||||
}, 100);
|
||||
}, []);
|
||||
|
||||
const onAddNode = useCallback(
|
||||
({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => {
|
||||
if (!reactFlowWrapper.current) return;
|
||||
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100;
|
||||
const mouseY = (position.y - reactFlowBounds.top - y) / zoom;
|
||||
|
||||
setNodes((state) =>
|
||||
state.concat(
|
||||
appModule2FlowNode({
|
||||
item: {
|
||||
...template,
|
||||
moduleId: nanoid(),
|
||||
position: { x: mouseX, y: mouseY }
|
||||
},
|
||||
onChangeNode,
|
||||
onDelNode,
|
||||
onDelEdge,
|
||||
onCopyNode,
|
||||
onCollectionNode
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
[x, zoom, y]
|
||||
);
|
||||
const onDelNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
setNodes((state) => state.filter((item) => item.id !== nodeId));
|
||||
setEdges((state) => state.filter((edge) => edge.source !== nodeId && edge.target !== nodeId));
|
||||
},
|
||||
[setEdges, setNodes]
|
||||
);
|
||||
const onDelEdge = useCallback(
|
||||
({
|
||||
moduleId,
|
||||
sourceHandle,
|
||||
targetHandle
|
||||
}: {
|
||||
moduleId: string;
|
||||
sourceHandle?: string;
|
||||
targetHandle?: string;
|
||||
}) => {
|
||||
if (!sourceHandle && !targetHandle) return;
|
||||
setEdges((state) =>
|
||||
state.filter((edge) => {
|
||||
if (edge.source === moduleId && edge.sourceHandle === sourceHandle) return false;
|
||||
if (edge.target === moduleId && edge.targetHandle === targetHandle) return false;
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
},
|
||||
[setEdges]
|
||||
);
|
||||
const onCopyNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
setNodes((nodes) => {
|
||||
const node = nodes.find((node) => node.id === nodeId);
|
||||
if (!node) return nodes;
|
||||
const template = {
|
||||
logo: node.data.logo,
|
||||
name: node.data.name,
|
||||
intro: node.data.intro,
|
||||
description: node.data.description,
|
||||
flowType: node.data.flowType,
|
||||
inputs: node.data.inputs,
|
||||
outputs: node.data.outputs,
|
||||
showStatus: node.data.showStatus
|
||||
};
|
||||
return nodes.concat(
|
||||
appModule2FlowNode({
|
||||
item: {
|
||||
...template,
|
||||
moduleId: nanoid(),
|
||||
position: { x: node.position.x + 200, y: node.position.y + 50 }
|
||||
},
|
||||
onChangeNode,
|
||||
onDelNode,
|
||||
onDelEdge,
|
||||
onCopyNode,
|
||||
onCollectionNode
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
[setNodes]
|
||||
);
|
||||
const onCollectionNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
console.log(nodes.find((node) => node.id === nodeId));
|
||||
},
|
||||
[nodes]
|
||||
);
|
||||
|
||||
const flow2AppModules = useCallback(() => {
|
||||
const modules: AppModuleItemType[] = nodes.map((item) => ({
|
||||
moduleId: item.data.moduleId,
|
||||
@@ -271,106 +113,6 @@ const AppEdit = ({ app, onCloseSettings }: Props) => {
|
||||
});
|
||||
return modules;
|
||||
}, [edges, nodes]);
|
||||
const onChangeNode = useCallback(
|
||||
({ moduleId, key, type = 'inputs', value }: FlowModuleItemChangeProps) => {
|
||||
setNodes((nodes) =>
|
||||
nodes.map((node) => {
|
||||
if (node.id !== moduleId) return node;
|
||||
|
||||
const updateObj: Record<string, any> = {};
|
||||
|
||||
if (type === 'inputs') {
|
||||
updateObj.inputs = node.data.inputs.map((item) => (item.key === key ? value : item));
|
||||
} else if (type === 'addInput') {
|
||||
const input = node.data.inputs.find((input) => input.key === value.key);
|
||||
if (input) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: 'key 重复'
|
||||
});
|
||||
updateObj.inputs = node.data.inputs;
|
||||
} else {
|
||||
updateObj.inputs = node.data.inputs.concat(value);
|
||||
}
|
||||
} else if (type === 'delInput') {
|
||||
onDelEdge({ moduleId, targetHandle: key });
|
||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== key);
|
||||
} else if (type === 'attr') {
|
||||
updateObj[key] = value;
|
||||
} else if (type === 'outputs') {
|
||||
// del output connect
|
||||
const delOutputs = node.data.outputs.filter(
|
||||
(item) => !value.find((output: FlowOutputTargetItemType) => output.key === item.key)
|
||||
);
|
||||
delOutputs.forEach((output) => {
|
||||
onDelEdge({ moduleId, sourceHandle: output.key });
|
||||
});
|
||||
updateObj.outputs = value;
|
||||
}
|
||||
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
...updateObj
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const onDelConnect = useCallback((id: string) => {
|
||||
setEdges((state) => state.filter((item) => item.id !== id));
|
||||
}, []);
|
||||
const onConnect = useCallback(
|
||||
({ connect }: { connect: Connection }) => {
|
||||
const source = nodes.find((node) => node.id === connect.source)?.data;
|
||||
const sourceType = (() => {
|
||||
if (source?.flowType === FlowModuleTypeEnum.classifyQuestion) {
|
||||
return FlowValueTypeEnum.boolean;
|
||||
}
|
||||
return source?.outputs.find((output) => output.key === connect.sourceHandle)?.valueType;
|
||||
})();
|
||||
|
||||
const targetType = nodes
|
||||
.find((node) => node.id === connect.target)
|
||||
?.data?.inputs.find((input) => input.key === connect.targetHandle)?.valueType;
|
||||
|
||||
if (!sourceType || !targetType) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('app.Connection is invalid')
|
||||
});
|
||||
}
|
||||
if (
|
||||
sourceType !== FlowValueTypeEnum.any &&
|
||||
targetType !== FlowValueTypeEnum.any &&
|
||||
sourceType !== targetType
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('app.Connection type is different')
|
||||
});
|
||||
}
|
||||
|
||||
setEdges((state) =>
|
||||
addEdge(
|
||||
{
|
||||
...connect,
|
||||
type: 'buttonedge',
|
||||
animated: true,
|
||||
data: {
|
||||
onDelete: onDelConnect
|
||||
}
|
||||
},
|
||||
state
|
||||
)
|
||||
);
|
||||
},
|
||||
[nodes]
|
||||
);
|
||||
|
||||
const { mutate: onclickSave, isLoading } = useRequest({
|
||||
mutationFn: () => {
|
||||
@@ -386,49 +128,8 @@ const AppEdit = ({ app, onCloseSettings }: Props) => {
|
||||
}
|
||||
});
|
||||
|
||||
const initData = useCallback(
|
||||
(modules: AppModuleItemType[]) => {
|
||||
const edges = appModule2FlowEdge({
|
||||
modules,
|
||||
onDelete: onDelConnect
|
||||
});
|
||||
setEdges(edges);
|
||||
|
||||
setNodes(
|
||||
modules.map((item) =>
|
||||
appModule2FlowNode({
|
||||
item,
|
||||
onChangeNode,
|
||||
onDelNode,
|
||||
onDelEdge,
|
||||
onCopyNode,
|
||||
onCollectionNode
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
onFixView();
|
||||
},
|
||||
[
|
||||
onDelConnect,
|
||||
setEdges,
|
||||
setNodes,
|
||||
onFixView,
|
||||
onChangeNode,
|
||||
onDelNode,
|
||||
onDelEdge,
|
||||
onCopyNode,
|
||||
onCollectionNode
|
||||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
initData(JSON.parse(JSON.stringify(app.modules)));
|
||||
}, [app.modules]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* header */}
|
||||
<Flex
|
||||
py={3}
|
||||
px={[2, 5, 8]}
|
||||
@@ -515,6 +216,38 @@ const AppEdit = ({ app, onCloseSettings }: Props) => {
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
||||
<ChatTest
|
||||
ref={ChatTestRef}
|
||||
modules={testModules}
|
||||
app={app}
|
||||
onClose={() => setTestModules(undefined)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
const Header = React.memo(FlowHeader);
|
||||
|
||||
const AppEdit = (props: Props) => {
|
||||
const { app } = props;
|
||||
|
||||
const {
|
||||
isOpen: isOpenTemplate,
|
||||
onOpen: onOpenTemplate,
|
||||
onClose: onCloseTemplate
|
||||
} = useDisclosure();
|
||||
|
||||
const { reactFlowWrapper, nodes, onNodesChange, edges, onEdgesChange, onConnect, initData } =
|
||||
useFlowStore();
|
||||
|
||||
useEffect(() => {
|
||||
initData(JSON.parse(JSON.stringify(app.modules)));
|
||||
}, [app.modules]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* header */}
|
||||
<Header {...props} />
|
||||
<Box
|
||||
minH={'400px'}
|
||||
flex={'1 0 0'}
|
||||
@@ -571,43 +304,24 @@ const AppEdit = ({ app, onCloseSettings }: Props) => {
|
||||
<Controls position={'bottom-right'} style={{ display: 'flex' }} showInteractive={false} />
|
||||
</ReactFlow>
|
||||
|
||||
<TemplateList
|
||||
isOpen={isOpenTemplate}
|
||||
nodes={nodes}
|
||||
onAddNode={onAddNode}
|
||||
onClose={onCloseTemplate}
|
||||
/>
|
||||
<ChatTest
|
||||
ref={ChatTestRef}
|
||||
modules={testModules}
|
||||
app={app}
|
||||
onClose={() => setTestModules(undefined)}
|
||||
/>
|
||||
<TemplateList isOpen={isOpenTemplate} nodes={nodes} onClose={onCloseTemplate} />
|
||||
</Box>
|
||||
{isOpenImport && (
|
||||
<ImportSettings
|
||||
onClose={onCloseImport}
|
||||
onSuccess={(data) => {
|
||||
setEdges([]);
|
||||
setNodes([]);
|
||||
setTimeout(() => {
|
||||
initData(data);
|
||||
}, 10);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Flow = (data: Props) => (
|
||||
<Box h={'100%'} position={'fixed'} zIndex={999} top={0} left={0} right={0} bottom={0}>
|
||||
<ReactFlowProvider>
|
||||
<Flex h={'100%'} flexDirection={'column'} bg={'#fff'}>
|
||||
{!!data.app._id && <AppEdit {...data} />}
|
||||
</Flex>
|
||||
</ReactFlowProvider>
|
||||
</Box>
|
||||
);
|
||||
const Flow = (data: Props) => {
|
||||
return (
|
||||
<Box h={'100%'} position={'fixed'} zIndex={999} top={0} left={0} right={0} bottom={0}>
|
||||
<ReactFlowProvider>
|
||||
<FlowProvider>
|
||||
<Flex h={'100%'} flexDirection={'column'} bg={'#fff'}>
|
||||
{!!data.app._id && <AppEdit {...data} />}
|
||||
</Flex>
|
||||
</FlowProvider>
|
||||
</ReactFlowProvider>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Flow);
|
||||
|
@@ -17,15 +17,10 @@ import BasicEdit from './components/BasicEdit';
|
||||
import { serviceSideProps } from '@/utils/web/i18n';
|
||||
|
||||
const AdEdit = dynamic(() => import('./components/AdEdit'), {
|
||||
ssr: false,
|
||||
loading: () => <Loading />
|
||||
});
|
||||
const OutLink = dynamic(() => import('./components/OutLink'), {
|
||||
ssr: false
|
||||
});
|
||||
const Logs = dynamic(() => import('./components/Logs'), {
|
||||
ssr: false
|
||||
});
|
||||
const OutLink = dynamic(() => import('./components/OutLink'), {});
|
||||
const Logs = dynamic(() => import('./components/Logs'), {});
|
||||
|
||||
enum TabEnum {
|
||||
'basicEdit' = 'basicEdit',
|
||||
|
@@ -7,7 +7,7 @@ import type { ClassifyQuestionAgentItemType } from '@/types/app';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { SpecialInputKeyEnum } from '@/constants/flow';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
import { replaceVariable } from '@/utils/common/tools/text';
|
||||
import { Prompt_CQJson } from '@/prompts/core/agent';
|
||||
import { defaultCQModel } from '@/pages/api/system/getInitData';
|
||||
|
@@ -6,7 +6,7 @@ import { getAIChatApi, axiosConfig } from '@fastgpt/core/aiApi/config';
|
||||
import type { ContextExtractAgentItemType } from '@/types/app';
|
||||
import { ContextExtractEnum } from '@/constants/flow/flowField';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
import { Prompt_ExtractJson } from '@/prompts/core/agent';
|
||||
import { replaceVariable } from '@/utils/common/tools/text';
|
||||
import { defaultExtractModel } from '@/pages/api/system/getInitData';
|
||||
|
@@ -19,7 +19,7 @@ import { defaultQuotePrompt, defaultQuoteTemplate } from '@/prompts/core/AIChat'
|
||||
import type { AIChatProps } from '@/types/core/aiChat';
|
||||
import { replaceVariable } from '@/utils/common/tools/text';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
import { Readable } from 'stream';
|
||||
import { responseWrite, responseWriteController } from '@/service/common/stream';
|
||||
import { addLog } from '@/service/utils/tools';
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { ChatItemType } from '@/types/chat';
|
||||
import type { ModuleDispatchProps } from '@/types/core/modules';
|
||||
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
export type HistoryProps = ModuleDispatchProps<{
|
||||
maxContext: number;
|
||||
[SystemInputEnum.history]: ChatItemType[];
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import type { ModuleDispatchProps } from '@/types/core/modules';
|
||||
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
export type UserChatInputProps = ModuleDispatchProps<{
|
||||
[SystemInputEnum.userChatInput]: string;
|
||||
}>;
|
||||
|
@@ -7,8 +7,7 @@ import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||
import type { QuoteItemType } from '@/types/chat';
|
||||
import { PgDatasetTableName } from '@/constants/plugin';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
type KBSearchProps = ModuleDispatchProps<{
|
||||
kbList: SelectedDatasetType;
|
||||
similarity: number;
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { sseResponseEventEnum, TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import { sseResponse } from '@/service/utils/tools';
|
||||
import { textAdaptGptResponse } from '@/utils/adapt';
|
||||
import type { ModuleDispatchProps } from '@/types/core/modules';
|
||||
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
export type AnswerProps = ModuleDispatchProps<{
|
||||
text: string;
|
||||
}>;
|
||||
|
@@ -2,8 +2,7 @@ import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import { HttpPropsEnum } from '@/constants/flow/flowField';
|
||||
import { ChatHistoryItemResType } from '@/types/chat';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||
|
||||
import type { ModuleDispatchProps } from '@/types/core/chat/type';
|
||||
export type HttpRequestProps = ModuleDispatchProps<{
|
||||
[HttpPropsEnum.url]: string;
|
||||
[key: string]: any;
|
||||
|
6
projects/app/src/types/app.d.ts
vendored
6
projects/app/src/types/app.d.ts
vendored
@@ -6,7 +6,11 @@ import {
|
||||
ModulesInputItemTypeEnum,
|
||||
VariableInputEnum
|
||||
} from '../constants/app';
|
||||
import type { FlowInputItemType, FlowOutputItemType, FlowOutputTargetItemType } from './flow';
|
||||
import type {
|
||||
FlowInputItemType,
|
||||
FlowOutputItemType,
|
||||
FlowOutputTargetItemType
|
||||
} from '@/types/core/app/flow';
|
||||
import type { AppSchema, ChatSchema, kbSchema } from './mongoSchema';
|
||||
import { ChatModelType } from '@/constants/model';
|
||||
import { FlowValueTypeEnum } from '@/constants/flow';
|
||||
|
@@ -59,17 +59,4 @@ export type FlowModuleTemplateType = {
|
||||
};
|
||||
export type FlowModuleItemType = FlowModuleTemplateType & {
|
||||
moduleId: string;
|
||||
onChangeNode: (e: FlowModuleItemChangeProps) => void;
|
||||
onDelNode: (id: string) => void;
|
||||
onCopyNode: (id: string) => void;
|
||||
onCollectionNode: (id: string) => void;
|
||||
onDelEdge: ({
|
||||
moduleId,
|
||||
sourceHandle,
|
||||
targetHandle
|
||||
}: {
|
||||
moduleId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}) => void;
|
||||
};
|
15
projects/app/src/types/core/chat/type.d.ts
vendored
15
projects/app/src/types/core/chat/type.d.ts
vendored
@@ -1,3 +1,18 @@
|
||||
import type { ChatCompletionRequestMessage } from '@fastgpt/core/aiApi/type';
|
||||
import type { NextApiResponse } from 'next';
|
||||
import { RunningModuleItemType } from '@/types/app';
|
||||
import { UserModelSchema } from '@/types/mongoSchema';
|
||||
|
||||
export type MessageItemType = ChatCompletionRequestMessage & { dataId?: string };
|
||||
|
||||
// module dispatch props type
|
||||
export type ModuleDispatchProps<T> = {
|
||||
res: NextApiResponse;
|
||||
moduleName: string;
|
||||
stream: boolean;
|
||||
detail: boolean;
|
||||
variables: Record<string, any>;
|
||||
outputs: RunningModuleItemType['outputs'];
|
||||
userOpenaiAccount?: UserModelSchema['openaiAccount'];
|
||||
inputs: T;
|
||||
};
|
||||
|
15
projects/app/src/types/core/modules.d.ts
vendored
15
projects/app/src/types/core/modules.d.ts
vendored
@@ -1,15 +0,0 @@
|
||||
import type { NextApiResponse } from 'next';
|
||||
import { RunningModuleItemType } from '../app';
|
||||
import { UserModelSchema } from '../mongoSchema';
|
||||
|
||||
// module dispatch props type
|
||||
export type ModuleDispatchProps<T> = {
|
||||
res: NextApiResponse;
|
||||
moduleName: string;
|
||||
stream: boolean;
|
||||
detail: boolean;
|
||||
variables: Record<string, any>;
|
||||
outputs: RunningModuleItemType['outputs'];
|
||||
userOpenaiAccount?: UserModelSchema['openaiAccount'];
|
||||
inputs: T;
|
||||
};
|
@@ -6,7 +6,7 @@ import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/core/aiApi/consta
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import type { MessageItemType } from '@/types/core/chat/type';
|
||||
import type { AppModuleItemType } from '@/types/app';
|
||||
import type { FlowModuleItemType } from '@/types/flow';
|
||||
import type { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import type { Edge, Node } from 'reactflow';
|
||||
import { connectionLineStyle } from '@/constants/flow';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
@@ -61,19 +61,9 @@ export const textAdaptGptResponse = ({
|
||||
};
|
||||
|
||||
export const appModule2FlowNode = ({
|
||||
item,
|
||||
onChangeNode,
|
||||
onDelNode,
|
||||
onDelEdge,
|
||||
onCopyNode,
|
||||
onCollectionNode
|
||||
item
|
||||
}: {
|
||||
item: AppModuleItemType;
|
||||
onChangeNode: FlowModuleItemType['onChangeNode'];
|
||||
onDelNode: FlowModuleItemType['onDelNode'];
|
||||
onDelEdge: FlowModuleItemType['onDelEdge'];
|
||||
onCopyNode: FlowModuleItemType['onCopyNode'];
|
||||
onCollectionNode: FlowModuleItemType['onCollectionNode'];
|
||||
}): Node<FlowModuleItemType> => {
|
||||
// init some static data
|
||||
const template =
|
||||
@@ -110,12 +100,7 @@ export const appModule2FlowNode = ({
|
||||
...(templateOutput ? templateOutput : output),
|
||||
targets: output.targets || []
|
||||
};
|
||||
}),
|
||||
onChangeNode,
|
||||
onDelNode,
|
||||
onDelEdge,
|
||||
onCopyNode,
|
||||
onCollectionNode
|
||||
})
|
||||
};
|
||||
|
||||
return {
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
} from '@/constants/flow';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||
import { FlowInputItemType } from '@/types/flow';
|
||||
import type { FlowInputItemType } from '@/types/core/app/flow';
|
||||
import type { AIChatProps } from '@/types/core/aiChat';
|
||||
import { getGuideModule, splitGuideModule } from '@/components/ChatBox/utils';
|
||||
|
||||
|
Reference in New Issue
Block a user