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:
Archer
2024-02-05 00:51:46 +08:00
committed by GitHub
parent ec8e2512bc
commit 51bbdf26a3
68 changed files with 4118 additions and 3787 deletions

View File

@@ -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} />

View File

@@ -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');

View File

@@ -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>

View File

@@ -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>
);

View File

@@ -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}>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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}
/>
);
};

View File

@@ -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;

View File

@@ -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')),