mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 18:48:55 +00:00
4.6.8-production (#822)
* Json completion (#16) * json-completion * fix duplicate * fix * fix: config json * feat: query extension * perf: i18n * 468 doc * json editor * perf: doc * perf: default extension model * docker file * doc * perf: token count * perf: search extension * format * perf: some constants data --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
@@ -39,8 +39,8 @@ function Row({
|
||||
{...(isCodeBlock
|
||||
? { transform: 'translateY(-3px)' }
|
||||
: value
|
||||
? { px: 3, py: 1, border: theme.borders.base }
|
||||
: {})}
|
||||
? { px: 3, py: 1, border: theme.borders.base }
|
||||
: {})}
|
||||
>
|
||||
{value && <Markdown source={strValue} />}
|
||||
{rawDom}
|
||||
@@ -129,126 +129,154 @@ const ResponseBox = React.memo(function ResponseBox({
|
||||
<Tabs list={list} activeId={currentTab} onChange={setCurrentTab} />
|
||||
</Box>
|
||||
<Box py={2} px={4} flex={'1 0 0'} overflow={'auto'}>
|
||||
<Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName)} />
|
||||
{activeModule?.price !== undefined && (
|
||||
<>
|
||||
<Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName)} />
|
||||
{activeModule?.price !== undefined && (
|
||||
<Row
|
||||
label={t('core.chat.response.module price')}
|
||||
value={`¥${formatStorePrice2Read(activeModule?.price)}`}
|
||||
/>
|
||||
)}
|
||||
<Row
|
||||
label={t('core.chat.response.module price')}
|
||||
value={`¥${formatStorePrice2Read(activeModule?.price)}`}
|
||||
label={t('core.chat.response.module time')}
|
||||
value={`${activeModule?.runningTime || 0}s`}
|
||||
/>
|
||||
)}
|
||||
<Row
|
||||
label={t('core.chat.response.module time')}
|
||||
value={`${activeModule?.runningTime || 0}s`}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module model')} value={activeModule?.model} />
|
||||
<Row label={t('wallet.bill.Chars length')} value={`${activeModule?.charsLength}`} />
|
||||
<Row label={t('wallet.bill.Input Token Length')} value={`${activeModule?.inputTokens}`} />
|
||||
<Row label={t('wallet.bill.Output Token Length')} value={`${activeModule?.outputTokens}`} />
|
||||
<Row label={t('core.chat.response.module query')} value={activeModule?.query} />
|
||||
<Row
|
||||
label={t('core.chat.response.context total length')}
|
||||
value={activeModule?.contextTotalLen}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module model')} value={activeModule?.model} />
|
||||
<Row label={t('wallet.bill.Chars length')} value={`${activeModule?.charsLength}`} />
|
||||
<Row label={t('wallet.bill.Input Token Length')} value={`${activeModule?.inputTokens}`} />
|
||||
<Row
|
||||
label={t('wallet.bill.Output Token Length')}
|
||||
value={`${activeModule?.outputTokens}`}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module query')} value={activeModule?.query} />
|
||||
<Row
|
||||
label={t('core.chat.response.context total length')}
|
||||
value={activeModule?.contextTotalLen}
|
||||
/>
|
||||
</>
|
||||
|
||||
{/* ai chat */}
|
||||
<Row label={t('core.chat.response.module temperature')} value={activeModule?.temperature} />
|
||||
<Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
|
||||
<Row
|
||||
label={t('core.chat.response.module historyPreview')}
|
||||
rawDom={
|
||||
activeModule.historyPreview ? (
|
||||
<Box px={3} py={2} border={theme.borders.base} borderRadius={'md'}>
|
||||
{activeModule.historyPreview?.map((item, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
_notLast={{
|
||||
borderBottom: '1px solid',
|
||||
borderBottomColor: 'myWhite.700',
|
||||
mb: 2
|
||||
}}
|
||||
pb={2}
|
||||
>
|
||||
<Box fontWeight={'bold'}>{item.obj}</Box>
|
||||
<Box whiteSpace={'pre-wrap'}>{item.value}</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
/>
|
||||
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
|
||||
<>
|
||||
<Row
|
||||
label={t('core.chat.response.module quoteList')}
|
||||
rawDom={<QuoteList isShare={isShare} rawSearch={activeModule.quoteList} />}
|
||||
label={t('core.chat.response.module temperature')}
|
||||
value={activeModule?.temperature}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
|
||||
<Row
|
||||
label={t('core.chat.response.module historyPreview')}
|
||||
rawDom={
|
||||
activeModule.historyPreview ? (
|
||||
<Box px={3} py={2} border={theme.borders.base} borderRadius={'md'}>
|
||||
{activeModule.historyPreview?.map((item, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
_notLast={{
|
||||
borderBottom: '1px solid',
|
||||
borderBottomColor: 'myWhite.700',
|
||||
mb: 2
|
||||
}}
|
||||
pb={2}
|
||||
>
|
||||
<Box fontWeight={'bold'}>{item.obj}</Box>
|
||||
<Box whiteSpace={'pre-wrap'}>{item.value}</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
/>
|
||||
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.module quoteList')}
|
||||
rawDom={<QuoteList isShare={isShare} rawSearch={activeModule.quoteList} />}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* dataset search */}
|
||||
{activeModule?.searchMode && (
|
||||
<>
|
||||
{activeModule?.searchMode && (
|
||||
<Row
|
||||
label={t('core.dataset.search.search mode')}
|
||||
// @ts-ignore
|
||||
value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
|
||||
<Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
|
||||
<Row
|
||||
label={t('core.dataset.search.search mode')}
|
||||
// @ts-ignore
|
||||
value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
|
||||
label={t('core.chat.response.search using reRank')}
|
||||
value={activeModule?.searchUsingReRank}
|
||||
/>
|
||||
)}
|
||||
<Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
|
||||
<Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
|
||||
<Row
|
||||
label={t('core.chat.response.search using reRank')}
|
||||
value={activeModule?.searchUsingReRank}
|
||||
/>
|
||||
<Row
|
||||
label={t('core.chat.response.Extension model')}
|
||||
value={activeModule?.extensionModel}
|
||||
/>
|
||||
<Row
|
||||
label={t('wallet.bill.Extension result')}
|
||||
value={`${activeModule?.extensionResult}`}
|
||||
/>
|
||||
</>
|
||||
|
||||
{/* classify question */}
|
||||
<Row
|
||||
label={t('core.chat.response.module cq')}
|
||||
value={(() => {
|
||||
if (!activeModule?.cqList) return '';
|
||||
return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
|
||||
})()}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
|
||||
<>
|
||||
<Row
|
||||
label={t('core.chat.response.module cq')}
|
||||
value={(() => {
|
||||
if (!activeModule?.cqList) return '';
|
||||
return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
|
||||
})()}
|
||||
/>
|
||||
<Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
|
||||
</>
|
||||
|
||||
{/* extract */}
|
||||
<Row
|
||||
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)}`}
|
||||
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)}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* http */}
|
||||
{activeModule?.body && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http 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)}`}
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
{activeModule?.body && (
|
||||
<Row
|
||||
label={t('core.chat.response.module http 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)}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* plugin */}
|
||||
{activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.Plugin Resonse Detail')}
|
||||
rawDom={<ResponseBox response={activeModule.pluginDetail} isShare={isShare} />}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.pluginOutput && (
|
||||
<Row
|
||||
label={t('core.chat.response.plugin output')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
{activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && (
|
||||
<Row
|
||||
label={t('core.chat.response.Plugin Resonse Detail')}
|
||||
rawDom={<ResponseBox response={activeModule.pluginDetail} isShare={isShare} />}
|
||||
/>
|
||||
)}
|
||||
{activeModule?.pluginOutput && (
|
||||
<Row
|
||||
label={t('core.chat.response.plugin output')}
|
||||
value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
{/* text output */}
|
||||
<Row label={t('core.chat.response.text output')} value={activeModule?.textOutput} />
|
||||
|
@@ -1011,8 +1011,9 @@ 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');
|
||||
|
||||
|
@@ -90,7 +90,7 @@ const MySlider = ({
|
||||
borderRadius={'md'}
|
||||
transform={'translate(-50%, -155%)'}
|
||||
fontSize={'11px'}
|
||||
display={'none'}
|
||||
display={['block', 'none']}
|
||||
>
|
||||
<Box transform={'scale(0.9)'}>{value}</Box>
|
||||
</SliderMark>
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Grid } from '@chakra-ui/react';
|
||||
import { Box, Flex, Grid, Image } from '@chakra-ui/react';
|
||||
import type { GridProps } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
|
||||
// @ts-ignore
|
||||
interface Props extends GridProps {
|
||||
list: { id: string; label: string | React.ReactNode }[];
|
||||
list: { id: string; icon?: string; label: string | React.ReactNode }[];
|
||||
activeId: string;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
onChange: (id: string) => void;
|
||||
@@ -46,10 +47,11 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
{...props}
|
||||
>
|
||||
{list.map((item) => (
|
||||
<Box
|
||||
<Flex
|
||||
key={item.id}
|
||||
py={sizeMap.inlineP}
|
||||
textAlign={'center'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
borderBottom={'2px solid transparent'}
|
||||
px={3}
|
||||
whiteSpace={'nowrap'}
|
||||
@@ -68,8 +70,17 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
onChange(item.id);
|
||||
}}
|
||||
>
|
||||
{item.icon && (
|
||||
<>
|
||||
{item.icon.startsWith('/') ? (
|
||||
<Image mr={1} src={item.icon} alt={''} w={'16px'} />
|
||||
) : (
|
||||
<MyIcon mr={1} name={item.icon as any} w={'16px'} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{typeof item.label === 'string' ? t(item.label) : item.label}
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
|
@@ -34,14 +34,12 @@ const AIChatSettingsModal = ({
|
||||
onClose,
|
||||
onSuccess,
|
||||
defaultData,
|
||||
simpleModeTemplate = SimpleModeTemplate_FastGPT_Universal,
|
||||
pickerMenu = []
|
||||
}: {
|
||||
isAdEdit?: boolean;
|
||||
onClose: () => void;
|
||||
onSuccess: (e: AIChatModuleProps) => void;
|
||||
defaultData: AIChatModuleProps;
|
||||
simpleModeTemplate?: AppSimpleEditConfigTemplateType;
|
||||
pickerMenu?: EditorVariablePickerType[];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -160,119 +158,112 @@ const AIChatSettingsModal = ({
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.temperature && (
|
||||
<Flex mb={10} mt={isAdEdit ? 8 : 6}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Temperature')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: t('core.app.deterministic'), value: 0 },
|
||||
{ label: t('core.app.Random'), value: 10 }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={0}
|
||||
max={10}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatTemperature)}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatTemperature, e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.maxToken && (
|
||||
<Flex mt={5} mb={5}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Max tokens')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${tokenLimit}`, value: tokenLimit }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatMaxToken)}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatMaxToken, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex mb={10} mt={isAdEdit ? 8 : 6}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Temperature')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: t('core.app.deterministic'), value: 0 },
|
||||
{ label: t('core.app.Random'), value: 10 }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={0}
|
||||
max={10}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatTemperature)}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatTemperature, e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex mt={5} mb={5}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
{t('core.app.Max tokens')}
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${tokenLimit}`, value: tokenLimit }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.aiChatMaxToken)}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatMaxToken, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.quoteTemplate && (
|
||||
<Box>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote templates')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box flex={1} />
|
||||
<Box
|
||||
{...selectTemplateBtn}
|
||||
onClick={() =>
|
||||
setSelectTemplateData({
|
||||
title: t('core.app.Select quote template'),
|
||||
templates: Prompt_QuoteTemplateList
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('common.Select template')}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<PromptEditor
|
||||
variables={quoteTemplateVariables}
|
||||
title={t('core.app.Quote templates')}
|
||||
placeholder={t('template.Quote Content Tip', {
|
||||
<Box>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote templates')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
value={aiChatQuoteTemplate}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuoteTemplate, e);
|
||||
// setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{simpleModeTemplate?.systemForm?.aiSettings?.quotePrompt && (
|
||||
<Box mt={4}>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote prompt')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value })}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<PromptEditor
|
||||
variables={quotePromptVariables}
|
||||
title={t('core.app.Quote prompt')}
|
||||
h={220}
|
||||
placeholder={t('template.Quote Prompt Tip', {
|
||||
default: Prompt_QuotePromptList[0].value
|
||||
})}
|
||||
value={aiChatQuotePrompt}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuotePrompt, e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box flex={1} />
|
||||
<Box
|
||||
{...selectTemplateBtn}
|
||||
onClick={() =>
|
||||
setSelectTemplateData({
|
||||
title: t('core.app.Select quote template'),
|
||||
templates: Prompt_QuoteTemplateList
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('common.Select template')}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<PromptEditor
|
||||
variables={quoteTemplateVariables}
|
||||
h={160}
|
||||
title={t('core.app.Quote templates')}
|
||||
placeholder={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
value={aiChatQuoteTemplate}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuoteTemplate, e);
|
||||
// setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box mt={4}>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
{t('core.app.Quote prompt')}
|
||||
<MyTooltip
|
||||
label={t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value })}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<PromptEditor
|
||||
variables={quotePromptVariables}
|
||||
title={t('core.app.Quote prompt')}
|
||||
h={230}
|
||||
placeholder={t('template.Quote Prompt Tip', {
|
||||
default: Prompt_QuotePromptList[0].value
|
||||
})}
|
||||
value={aiChatQuotePrompt}
|
||||
onChange={(e) => {
|
||||
setValue(ModuleInputKeyEnum.aiChatQuotePrompt, e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant={'whiteBase'} onClick={onClose}>
|
||||
|
@@ -7,6 +7,7 @@ import {
|
||||
Flex,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Switch,
|
||||
Textarea,
|
||||
useTheme
|
||||
} from '@chakra-ui/react';
|
||||
@@ -23,15 +24,27 @@ import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
import MyRadio from '@/components/common/MyRadio';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import SelectAiModel from '@/components/Select/SelectAiModel';
|
||||
|
||||
type DatasetParamsProps = {
|
||||
export type DatasetParamsProps = {
|
||||
searchMode: `${DatasetSearchModeEnum}`;
|
||||
searchEmptyText?: string;
|
||||
limit?: number;
|
||||
similarity?: number;
|
||||
usingReRank?: boolean;
|
||||
datasetSearchUsingExtensionQuery?: boolean;
|
||||
datasetSearchExtensionModel?: string;
|
||||
datasetSearchExtensionBg?: string;
|
||||
|
||||
maxTokens?: number;
|
||||
searchEmptyText?: string;
|
||||
};
|
||||
enum SearchSettingTabEnum {
|
||||
searchMode = 'searchMode',
|
||||
limit = 'limit',
|
||||
queryExtension = 'queryExtension'
|
||||
}
|
||||
|
||||
const DatasetParamsModal = ({
|
||||
searchMode = DatasetSearchModeEnum.embedding,
|
||||
@@ -40,22 +53,39 @@ const DatasetParamsModal = ({
|
||||
similarity,
|
||||
usingReRank,
|
||||
maxTokens = 3000,
|
||||
datasetSearchUsingExtensionQuery,
|
||||
datasetSearchExtensionModel,
|
||||
datasetSearchExtensionBg,
|
||||
onClose,
|
||||
onSuccess
|
||||
}: DatasetParamsProps & { onClose: () => void; onSuccess: (e: DatasetParamsProps) => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { reRankModelList } = useSystemStore();
|
||||
const { reRankModelList, llmModelList } = useSystemStore();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const { register, setValue, getValues, handleSubmit } = useForm<DatasetParamsProps>({
|
||||
const [currentTabType, setCurrentTabType] = useState(SearchSettingTabEnum.searchMode);
|
||||
|
||||
const { register, setValue, getValues, handleSubmit, watch } = useForm<DatasetParamsProps>({
|
||||
defaultValues: {
|
||||
searchEmptyText,
|
||||
limit,
|
||||
similarity,
|
||||
searchMode,
|
||||
usingReRank
|
||||
usingReRank,
|
||||
datasetSearchUsingExtensionQuery,
|
||||
datasetSearchExtensionModel: datasetSearchExtensionModel ?? llmModelList[0]?.model,
|
||||
datasetSearchExtensionBg
|
||||
}
|
||||
});
|
||||
const datasetSearchUsingCfrForm = watch('datasetSearchUsingExtensionQuery');
|
||||
const queryExtensionModel = watch('datasetSearchExtensionModel');
|
||||
const cfbBgDesc = watch('datasetSearchExtensionBg');
|
||||
|
||||
const chatModelSelectList = (() =>
|
||||
llmModelList.map((item) => ({
|
||||
value: item.model,
|
||||
label: item.name
|
||||
})))();
|
||||
|
||||
const searchModeList = useMemo(() => {
|
||||
const list = Object.values(DatasetSearchModeMap);
|
||||
@@ -82,125 +112,209 @@ const DatasetParamsModal = ({
|
||||
iconSrc="/imgs/modal/params.svg"
|
||||
title={t('core.dataset.search.Dataset Search Params')}
|
||||
w={['90vw', '550px']}
|
||||
h={['90vh', 'auto']}
|
||||
isCentered={searchEmptyText !== undefined}
|
||||
>
|
||||
<ModalBody flex={['1 0 0', 'auto']} overflow={'auto'}>
|
||||
<MyRadio
|
||||
gridGap={2}
|
||||
gridTemplateColumns={'repeat(1,1fr)'}
|
||||
list={searchModeList}
|
||||
value={getValues('searchMode')}
|
||||
onChange={(e) => {
|
||||
setValue('searchMode', e as `${DatasetSearchModeEnum}`);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
<ModalBody flex={'auto'} overflow={'auto'}>
|
||||
<Tabs
|
||||
mb={3}
|
||||
list={[
|
||||
{
|
||||
icon: 'modal/setting',
|
||||
label: t('core.dataset.search.search mode'),
|
||||
id: SearchSettingTabEnum.searchMode
|
||||
},
|
||||
{
|
||||
icon: 'support/outlink/apikeyFill',
|
||||
label: t('core.dataset.search.Filter'),
|
||||
id: SearchSettingTabEnum.limit
|
||||
},
|
||||
{
|
||||
label: t('core.module.template.Query extension'),
|
||||
id: SearchSettingTabEnum.queryExtension,
|
||||
icon: '/imgs/module/cfr.svg'
|
||||
}
|
||||
]}
|
||||
activeId={currentTabType}
|
||||
onChange={(e) => setCurrentTabType(e as any)}
|
||||
/>
|
||||
{usingReRank !== undefined && reRankModelList.length > 0 && (
|
||||
{currentTabType === SearchSettingTabEnum.searchMode && (
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'16px'}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
{...(getValues('usingReRank')
|
||||
? {
|
||||
borderColor: 'primary.400'
|
||||
}
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
<MyRadio
|
||||
gridGap={2}
|
||||
gridTemplateColumns={'repeat(1,1fr)'}
|
||||
list={searchModeList}
|
||||
value={getValues('searchMode')}
|
||||
onChange={(e) => {
|
||||
setValue('searchMode', e as `${DatasetSearchModeEnum}`);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
>
|
||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||
<Box>{t('core.dataset.search.ReRank')}</Box>
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t('core.dataset.search.ReRank desc')}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||
<Checkbox colorScheme="primary" isChecked={getValues('usingReRank')} size="lg" />
|
||||
<Box position={'absolute'} top={0} right={0} bottom={0} left={0} zIndex={1}></Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
/>
|
||||
{usingReRank !== undefined && reRankModelList.length > 0 && (
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'16px'}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
{...(getValues('usingReRank')
|
||||
? {
|
||||
borderColor: 'primary.400'
|
||||
}
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
>
|
||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||
<Box>{t('core.dataset.search.ReRank')}</Box>
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t('core.dataset.search.ReRank desc')}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||
<Checkbox
|
||||
colorScheme="primary"
|
||||
isChecked={getValues('usingReRank')}
|
||||
size="lg"
|
||||
/>
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
left={0}
|
||||
zIndex={1}
|
||||
></Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{limit !== undefined && (
|
||||
<Box display={['block', 'flex']} mt={5}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Max Tokens')}
|
||||
<MyTooltip label={t('core.dataset.search.Max Tokens Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: maxTokens, value: maxTokens }
|
||||
]}
|
||||
min={100}
|
||||
max={maxTokens}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.datasetMaxTokens) ?? 1000}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetMaxTokens, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
{currentTabType === SearchSettingTabEnum.limit && (
|
||||
<Box pt={5}>
|
||||
{limit !== undefined && (
|
||||
<Box display={['block', 'flex']}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Max Tokens')}
|
||||
<MyTooltip label={t('core.dataset.search.Max Tokens Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: maxTokens, value: maxTokens }
|
||||
]}
|
||||
min={100}
|
||||
max={maxTokens}
|
||||
step={50}
|
||||
value={getValues(ModuleInputKeyEnum.datasetMaxTokens) ?? 1000}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetMaxTokens, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{showSimilarity && (
|
||||
<Box display={['block', 'flex']} mt={10}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Min Similarity')}
|
||||
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '0', value: 0 },
|
||||
{ label: '1', value: 1 }
|
||||
]}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={getValues(ModuleInputKeyEnum.datasetSimilarity) ?? 0.5}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetSimilarity, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{searchEmptyText !== undefined && (
|
||||
<Box display={['block', 'flex']} pt={3}>
|
||||
<Box flex={'0 0 120px'} mb={[2, 0]}>
|
||||
{t('core.dataset.search.Empty result response')}
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Textarea
|
||||
rows={5}
|
||||
maxLength={500}
|
||||
placeholder={t('core.dataset.search.Empty result response Tips')}
|
||||
{...register('searchEmptyText')}
|
||||
></Textarea>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
{showSimilarity && (
|
||||
<Box display={['block', 'flex']} mt={5}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Min Similarity')}
|
||||
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '0', value: 0 },
|
||||
{ label: '1', value: 1 }
|
||||
]}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={getValues(ModuleInputKeyEnum.datasetSimilarity) ?? 0.5}
|
||||
onChange={(val) => {
|
||||
setValue(ModuleInputKeyEnum.datasetSimilarity, val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{searchEmptyText !== undefined && (
|
||||
<Box display={['block', 'flex']} pt={3}>
|
||||
<Box flex={'0 0 120px'} mb={[2, 0]}>
|
||||
{t('core.dataset.search.Empty result response')}
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Textarea
|
||||
rows={5}
|
||||
maxLength={500}
|
||||
placeholder={t('core.dataset.search.Empty result response Tips')}
|
||||
{...register('searchEmptyText')}
|
||||
></Textarea>
|
||||
{currentTabType === SearchSettingTabEnum.queryExtension && (
|
||||
<Box>
|
||||
<Box fontSize={'xs'} color={'myGray.500'}>
|
||||
{t('core.module.template.Query extension intro')}
|
||||
</Box>
|
||||
<Flex mt={3} alignItems={'center'}>
|
||||
<Box flex={'1 0 0'}>{t('core.dataset.search.Using query extension')}</Box>
|
||||
<Switch {...register('datasetSearchUsingExtensionQuery')} />
|
||||
</Flex>
|
||||
{datasetSearchUsingCfrForm === true && (
|
||||
<>
|
||||
<Flex mt={4} alignItems={'center'}>
|
||||
<Box flex={'0 0 100px'}>{t('core.ai.Model')}</Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<SelectAiModel
|
||||
width={'100%'}
|
||||
value={queryExtensionModel}
|
||||
list={chatModelSelectList}
|
||||
onchange={(val: any) => {
|
||||
setValue('datasetSearchExtensionModel', val);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box mt={3}>
|
||||
<Flex alignItems={'center'}>
|
||||
{t('core.app.edit.Query extension background prompt')}
|
||||
<MyTooltip label={t('core.app.edit.Query extension background tip')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Box mt={1}>
|
||||
<PromptEditor
|
||||
h={200}
|
||||
showOpenModal={false}
|
||||
placeholder={t('core.module.QueryExtension.placeholder')}
|
||||
value={cfbBgDesc}
|
||||
onChange={(e) => {
|
||||
setValue('datasetSearchExtensionBg', e);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</ModalBody>
|
||||
|
@@ -53,8 +53,8 @@ const TTSSelect = ({
|
||||
if (e === TTSTypeEnum.none || e === TTSTypeEnum.web) {
|
||||
onChange({ type: e as `${TTSTypeEnum}` });
|
||||
} else {
|
||||
const audioModel = audioSpeechModelList.find(
|
||||
(item) => item.voices?.find((voice) => voice.value === e)
|
||||
const audioModel = audioSpeechModelList.find((item) =>
|
||||
item.voices?.find((voice) => voice.value === e)
|
||||
);
|
||||
if (!audioModel) {
|
||||
return;
|
||||
|
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../render/NodeCard';
|
||||
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
|
||||
const NodeHttp = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
|
||||
return (
|
||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||
<Divider text="Input" />
|
||||
<Container>
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
};
|
||||
export default React.memo(NodeHttp);
|
@@ -61,8 +61,9 @@ const NodeCard = (props: Props) => {
|
||||
icon: 'common/refreshLight',
|
||||
label: t('plugin.Synchronous version'),
|
||||
onClick: () => {
|
||||
const pluginId = inputs.find((item) => item.key === ModuleInputKeyEnum.pluginId)
|
||||
?.value;
|
||||
const pluginId = inputs.find(
|
||||
(item) => item.key === ModuleInputKeyEnum.pluginId
|
||||
)?.value;
|
||||
if (!pluginId) return;
|
||||
openConfirm(async () => {
|
||||
try {
|
||||
|
@@ -1,11 +1,34 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { onChangeNode } from '../../../../FlowProvider';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import JSONEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
||||
import {
|
||||
formatEditorVariablePickerIcon,
|
||||
getGuideModule,
|
||||
splitGuideModule
|
||||
} from '@fastgpt/global/core/module/utils';
|
||||
|
||||
const JsonEditor = ({ item, moduleId }: RenderInputProps) => {
|
||||
const JsonEditor = ({ inputs = [], item, moduleId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodes } = useFlowProviderStore();
|
||||
|
||||
// get variable
|
||||
const variables = useMemo(() => {
|
||||
const globalVariables = formatEditorVariablePickerIcon(
|
||||
splitGuideModule(getGuideModule(nodes.map((node) => node.data)))?.variableModules || []
|
||||
);
|
||||
const moduleVariables = formatEditorVariablePickerIcon(
|
||||
inputs
|
||||
.filter((input) => input.edit)
|
||||
.map((item) => ({
|
||||
key: item.key,
|
||||
label: item.label
|
||||
}))
|
||||
);
|
||||
|
||||
return [...globalVariables, ...moduleVariables];
|
||||
}, [inputs, nodes]);
|
||||
|
||||
const update = useCallback(
|
||||
(value: string) => {
|
||||
@@ -28,10 +51,11 @@ const JsonEditor = ({ item, moduleId }: RenderInputProps) => {
|
||||
bg={'myWhite.400'}
|
||||
placeholder={t(item.placeholder || '')}
|
||||
resize
|
||||
defaultValue={item.value}
|
||||
value={item.value}
|
||||
onChange={(e) => {
|
||||
update(e);
|
||||
}}
|
||||
variables={variables}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@@ -7,19 +7,24 @@ import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import DatasetParamsModal from '@/components/core/module/DatasetParamsModal';
|
||||
import DatasetParamsModal, {
|
||||
DatasetParamsProps
|
||||
} from '@/components/core/module/DatasetParamsModal';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
|
||||
const { nodes } = useFlowProviderStore();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { llmModelList } = useSystemStore();
|
||||
const [data, setData] = useState({
|
||||
|
||||
const [data, setData] = useState<DatasetParamsProps>({
|
||||
searchMode: DatasetSearchModeEnum.embedding,
|
||||
limit: 5,
|
||||
similarity: 0.5,
|
||||
usingReRank: false
|
||||
usingReRank: false,
|
||||
datasetSearchUsingExtensionQuery: true,
|
||||
datasetSearchExtensionModel: llmModelList[0]?.model,
|
||||
datasetSearchExtensionBg: ''
|
||||
});
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
@@ -69,6 +74,7 @@ const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
|
||||
maxTokens={tokenLimit}
|
||||
onClose={onClose}
|
||||
onSuccess={(e) => {
|
||||
setData(e);
|
||||
for (let key in e) {
|
||||
const item = inputs.find((input) => input.key === key);
|
||||
if (!item) continue;
|
||||
|
@@ -25,7 +25,7 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
||||
[FlowNodeTypeEnum.answerNode]: dynamic(() => import('./components/nodes/NodeAnswer')),
|
||||
[FlowNodeTypeEnum.classifyQuestion]: dynamic(() => import('./components/nodes/NodeCQNode')),
|
||||
[FlowNodeTypeEnum.contentExtract]: dynamic(() => import('./components/nodes/NodeExtract')),
|
||||
[FlowNodeTypeEnum.httpRequest]: NodeSimple,
|
||||
[FlowNodeTypeEnum.httpRequest]: dynamic(() => import('./components/nodes/NodeHttp')),
|
||||
[FlowNodeTypeEnum.runApp]: NodeSimple,
|
||||
[FlowNodeTypeEnum.pluginInput]: dynamic(() => import('./components/nodes/NodePluginInput')),
|
||||
[FlowNodeTypeEnum.pluginOutput]: dynamic(() => import('./components/nodes/NodePluginOutput')),
|
||||
|
Reference in New Issue
Block a user