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

@@ -66,13 +66,13 @@ export async function getInitConfig() {
await Promise.all([
initGlobal(),
initSystemConfig(),
getSimpleModeTemplates(),
// getSimpleModeTemplates(),
getSystemVersion(),
getSystemPlugin()
]);
console.log({
simpleModeTemplates: global.simpleModeTemplates,
// simpleModeTemplates: global.simpleModeTemplates,
communityPlugins: global.communityPlugins
});
} catch (error) {
@@ -165,38 +165,38 @@ export function getSystemVersion() {
}
}
async function getSimpleModeTemplates() {
if (global.simpleModeTemplates && global.simpleModeTemplates.length > 0) return;
// async function getSimpleModeTemplates() {
// if (global.simpleModeTemplates && global.simpleModeTemplates.length > 0) return;
try {
const basePath =
process.env.NODE_ENV === 'development' ? 'data/simpleTemplates' : '/app/data/simpleTemplates';
// read data/simpleTemplates directory, get all json file
const files = readdirSync(basePath);
// filter json file
const filterFiles = files.filter((item) => item.endsWith('.json'));
// try {
// const basePath =
// process.env.NODE_ENV === 'development' ? 'data/simpleTemplates' : '/app/data/simpleTemplates';
// // read data/simpleTemplates directory, get all json file
// const files = readdirSync(basePath);
// // filter json file
// const filterFiles = files.filter((item) => item.endsWith('.json'));
// read json file
const fileTemplates = filterFiles.map((item) => {
const content = readFileSync(`${basePath}/${item}`, 'utf-8');
return {
id: item.replace('.json', ''),
...JSON.parse(content)
};
});
// // read json file
// const fileTemplates = filterFiles.map((item) => {
// const content = readFileSync(`${basePath}/${item}`, 'utf-8');
// return {
// id: item.replace('.json', ''),
// ...JSON.parse(content)
// };
// });
// fetch templates from plus
const plusTemplates = await getSimpleTemplatesFromPlus();
// // fetch templates from plus
// const plusTemplates = await getSimpleTemplatesFromPlus();
global.simpleModeTemplates = [
SimpleModeTemplate_FastGPT_Universal,
...plusTemplates,
...fileTemplates
];
} catch (error) {
global.simpleModeTemplates = [SimpleModeTemplate_FastGPT_Universal];
}
}
// global.simpleModeTemplates = [
// SimpleModeTemplate_FastGPT_Universal,
// ...plusTemplates,
// ...fileTemplates
// ];
// } catch (error) {
// global.simpleModeTemplates = [SimpleModeTemplate_FastGPT_Universal];
// }
// }
function getSystemPlugin() {
if (global.communityPlugins && global.communityPlugins.length > 0) return;

View File

@@ -294,7 +294,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
valueType: 'string',
targets: [
{
moduleId: 'vuc92c',
moduleId: 'datasetSearch',
key: 'userChatInput'
}
]
@@ -387,15 +387,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
value: true,
connected: false
},
{
key: 'datasetParamsModal',
type: 'selectDatasetParamsModal',
label: '',
valueType: 'any',
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
},
{
key: 'userChatInput',
type: 'target',
@@ -495,19 +486,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
label: '温度',
value: 0,
valueType: 'number',
min: 0,
max: 10,
step: 1,
markList: [
{
label: '严谨',
value: 0
},
{
label: '发散',
value: 10
}
],
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
@@ -518,19 +496,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
label: '回复上限',
value: maxToken,
valueType: 'number',
min: 100,
max: 4000,
step: 50,
markList: [
{
label: '100',
value: 100
},
{
label: '4000',
value: 4000
}
],
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
@@ -649,89 +614,6 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
targets: []
}
]
},
{
moduleId: 'vuc92c',
name: 'core.module.template.cfr',
avatar: '/imgs/module/cfr.svg',
flowType: 'cfr',
showStatus: true,
position: {
x: 758.2985382279098,
y: 1124.6527309337314
},
inputs: [
{
key: 'switch',
type: 'target',
label: 'core.module.input.label.switch',
valueType: 'any',
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
},
{
key: 'model',
type: 'selectExtractModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
value: getLLMModel().model,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
},
{
key: 'systemPrompt',
type: 'textarea',
label: 'core.module.input.label.cfr background',
max: 300,
value: formData.cfr.background,
valueType: 'string',
description: 'core.module.input.description.cfr background',
placeholder: 'core.module.input.placeholder.cfr background',
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
},
{
key: 'history',
type: 'numberInput',
label: 'core.module.input.label.chat history',
required: true,
min: 0,
max: 30,
valueType: 'chatHistory',
value: 6,
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
},
{
key: 'userChatInput',
type: 'target',
label: 'core.module.input.label.user question',
required: true,
valueType: 'string',
showTargetInApp: true,
showTargetInPlugin: true,
connected: true
}
],
outputs: [
{
key: 'system_text',
label: 'core.module.output.label.cfr result',
valueType: 'string',
type: 'source',
targets: [
{
moduleId: 'datasetSearch',
key: 'userChatInput'
}
]
}
]
}
];

View File

@@ -290,7 +290,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
valueType: 'string',
targets: [
{
moduleId: 'vuc92c',
moduleId: 'datasetSearch',
key: 'userChatInput'
}
]
@@ -335,19 +335,6 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
label: '最低相关性',
value: formData.dataset.similarity,
valueType: 'number',
min: 0,
max: 1,
step: 0.01,
markList: [
{
label: '0',
value: 0
},
{
label: '1',
value: 1
}
],
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
@@ -384,12 +371,33 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
connected: false
},
{
key: 'datasetParamsModal',
type: 'selectDatasetParamsModal',
key: 'datasetSearchUsingExtensionQuery',
type: 'hidden',
label: '',
valueType: 'any',
valueType: 'boolean',
showTargetInApp: false,
showTargetInPlugin: false,
value: formData.dataset.datasetSearchUsingExtensionQuery,
connected: false
},
{
key: 'datasetSearchExtensionBg',
type: 'hidden',
label: '',
valueType: 'string',
showTargetInApp: false,
showTargetInPlugin: false,
value: formData.dataset.datasetSearchExtensionBg,
connected: false
},
{
key: 'datasetSearchExtensionModel',
type: 'hidden',
label: '',
valueType: 'string',
showTargetInApp: false,
showTargetInPlugin: false,
value: formData.dataset.datasetSearchExtensionModel,
connected: false
},
{
@@ -659,89 +667,6 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
targets: []
}
]
},
{
moduleId: 'vuc92c',
name: 'core.module.template.cfr',
avatar: '/imgs/module/cfr.svg',
flowType: 'cfr',
showStatus: true,
position: {
x: 758.2985382279098,
y: 1124.6527309337314
},
inputs: [
{
key: 'switch',
type: 'target',
label: 'core.module.input.label.switch',
valueType: 'any',
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
},
{
key: 'model',
type: 'selectExtractModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
value: getLLMModel().model,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
},
{
key: 'systemPrompt',
type: 'textarea',
label: 'core.module.input.label.cfr background',
max: 300,
value: formData.cfr.background,
valueType: 'string',
description: 'core.module.input.description.cfr background',
placeholder: 'core.module.input.placeholder.cfr background',
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
},
{
key: 'history',
type: 'numberInput',
label: 'core.module.input.label.chat history',
required: true,
min: 0,
max: 30,
valueType: 'chatHistory',
value: 6,
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
},
{
key: 'userChatInput',
type: 'target',
label: 'core.module.input.label.user question',
required: true,
valueType: 'string',
showTargetInApp: true,
showTargetInPlugin: true,
connected: true
}
],
outputs: [
{
key: 'system_text',
label: 'core.module.output.label.cfr result',
valueType: 'string',
type: 'source',
targets: [
{
moduleId: 'datasetSearch',
key: 'userChatInput'
}
]
}
]
}
];

View File

@@ -9,7 +9,9 @@ import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { searchDatasetData } from '@/service/core/dataset/data/controller';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { searchQueryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
import { getLLMModel } from '@/service/core/ai/model';
import { queryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
import { datasetSearchQueryExtension } from '@fastgpt/service/core/dataset/search/utils';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -20,13 +22,16 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
limit = 1500,
similarity,
searchMode,
usingReRank
usingReRank,
datasetSearchUsingExtensionQuery = false,
datasetSearchExtensionModel,
datasetSearchExtensionBg = ''
} = req.body as SearchTestProps;
if (!datasetId || !text) {
throw new Error('缺少参数');
}
const start = Date.now();
// auth dataset role
@@ -37,20 +42,24 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
datasetId,
per: 'r'
});
// auth balance
await authTeamBalance(teamId);
// query extension
// const { queries } = await searchQueryExtension({
// query: text,
// model: global.llmModel[0].model
// });
const extensionModel =
datasetSearchUsingExtensionQuery && datasetSearchExtensionModel
? getLLMModel(datasetSearchExtensionModel)
: undefined;
const { concatQueries, rewriteQuery, aiExtensionResult } = await datasetSearchQueryExtension({
query: text,
extensionModel,
extensionBg: datasetSearchExtensionBg
});
const { searchRes, charsLength, ...result } = await searchDatasetData({
teamId,
rawQuery: text,
queries: [text],
reRankQuery: rewriteQuery,
queries: concatQueries,
model: dataset.vectorModel,
limit: Math.min(limit, 20000),
similarity,
@@ -65,7 +74,14 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
tmbId,
charsLength,
model: dataset.vectorModel,
source: apikey ? BillSourceEnum.api : BillSourceEnum.fastgpt
source: apikey ? BillSourceEnum.api : BillSourceEnum.fastgpt,
...(aiExtensionResult &&
extensionModel && {
extensionModel: extensionModel.name,
extensionInputTokens: aiExtensionResult.inputTokens,
extensionOutputTokens: aiExtensionResult.outputTokens
})
});
if (apikey) {
updateApiKeyUsage({

View File

@@ -1,61 +0,0 @@
import React, { useCallback, useState, useTransition } from 'react';
import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next';
import { Box, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
const CfrEditModal = ({
defaultValue = '',
onClose,
onFinish
}: {
defaultValue?: string;
onClose: () => void;
onFinish: (value: string) => void;
}) => {
const { t } = useTranslation();
const [value, setValue] = useState(defaultValue);
return (
<MyModal
isOpen
onClose={onClose}
iconSrc="/imgs/module/cfr.svg"
w={'500px'}
title={t('core.module.template.cfr')}
>
<ModalBody>
{t('core.app.edit.cfr background prompt')}
<MyTooltip label={t('core.app.edit.cfr background tip')} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
</MyTooltip>
<Box mt={1} flex={1}>
<PromptEditor
h={200}
showOpenModal={false}
placeholder={t('core.module.input.placeholder.cfr background')}
value={value}
onChange={(e) => {
setValue(e);
}}
/>
</Box>
</ModalBody>
<ModalFooter>
<Button
onClick={() => {
onFinish(value);
onClose();
}}
>
{t('common.Done')}
</Button>
</ModalFooter>
</MyModal>
);
};
export default React.memo(CfrEditModal);

View File

@@ -30,7 +30,6 @@ import MySelect from '@/components/Select';
import MyTooltip from '@/components/MyTooltip';
import Avatar from '@/components/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
import VariableEdit from '@/components/core/module/Flow/components/modules/VariableEdit';
import MyTextarea from '@/components/common/Textarea/MyTextarea/index';
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
@@ -45,7 +44,6 @@ const TTSSelect = dynamic(
() => import('@/components/core/module/Flow/components/modules/TTSSelect')
);
const QGSwitch = dynamic(() => import('@/components/core/module/Flow/components/modules/QGSwitch'));
const CfrEditModal = dynamic(() => import('./CfrEditModal'));
const EditForm = ({
divRef,
@@ -59,7 +57,7 @@ const EditForm = ({
const { t } = useTranslation();
const { appDetail, updateAppDetail } = useAppStore();
const { loadAllDatasets, allDatasets } = useDatasetStore();
const { isPc, llmModelList, reRankModelList, simpleModeTemplates } = useSystemStore();
const { isPc, llmModelList, reRankModelList } = useSystemStore();
const [refresh, setRefresh] = useState(false);
const [, startTst] = useTransition();
@@ -88,19 +86,16 @@ const EditForm = ({
onOpen: onOpenDatasetParams,
onClose: onCloseDatasetParams
} = useDisclosure();
const {
isOpen: isOpenCfrModal,
onOpen: onOpenCfrModal,
onClose: onCloseCfrModal
} = useDisclosure();
const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
content: t('core.app.edit.Confirm Save App Tip')
});
const aiSystemPrompt = watch('aiSettings.systemPrompt');
const selectLLMModel = watch('aiSettings.model');
const datasetSearchSetting = watch('dataset');
const variables = watch('userGuide.variables');
const formatVariables = useMemo(() => formatEditorVariablePickerIcon(variables), [variables]);
const aiSystemPrompt = watch('aiSettings.systemPrompt');
const searchMode = watch('dataset.searchMode');
const chatModelSelectList = (() =>
@@ -114,16 +109,9 @@ const EditForm = ({
[allDatasets, datasets]
);
const selectSimpleTemplate = (() =>
simpleModeTemplates?.find((item) => item.id === getValues('templateId')) ||
SimpleModeTemplate_FastGPT_Universal)();
const tokenLimit = useMemo(() => {
return (
llmModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
3000
);
}, [getValues, llmModelList]);
return llmModelList.find((item) => item.model === selectLLMModel)?.quoteMaxToken || 3000;
}, [selectLLMModel, llmModelList]);
const datasetSearchMode = useMemo(() => {
if (!searchMode) return '';
@@ -132,12 +120,11 @@ const EditForm = ({
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
mutationFn: async (data: AppSimpleEditFormType) => {
const modules = await postForm2Modules(data, data.templateId);
const modules = await postForm2Modules(data);
await updateAppDetail(appDetail._id, {
modules,
type: AppTypeEnum.simple,
simpleTemplateId: data.templateId,
permission: undefined
});
},
@@ -149,7 +136,6 @@ const EditForm = ({
['init', appDetail],
() => {
const formatVal = appModules2Form({
templateId: appDetail.simpleTemplateId,
modules: appDetail.modules
});
reset(formatVal);
@@ -228,7 +214,7 @@ const EditForm = ({
<Box px={4}>
<Box bg={'white'} borderRadius={'md'} borderWidth={'1px'} borderColor={'borderColor.base'}>
{/* simple mode select */}
<Flex {...BoxStyles}>
{/* <Flex {...BoxStyles}>
<Flex alignItems={'center'} flex={'1 0 0'}>
<MyIcon name={'core/app/simpleMode/template'} w={'20px'} />
<Box mx={2}>{t('core.app.simple.mode template select')}</Box>
@@ -248,237 +234,187 @@ const EditForm = ({
setRefresh(!refresh);
}}
/>
</Flex>
</Flex> */}
{/* ai */}
{selectSimpleTemplate?.systemForm?.aiSettings && (
<Box {...BoxStyles}>
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/ai'} w={'20px'} />
<Box ml={2} flex={1}>
{t('app.AI Settings')}
</Box>
{(selectSimpleTemplate.systemForm.aiSettings.maxToken ||
selectSimpleTemplate.systemForm.aiSettings.temperature ||
selectSimpleTemplate.systemForm.aiSettings.quoteTemplate ||
selectSimpleTemplate.systemForm.aiSettings.quotePrompt) && (
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
<MyIcon mr={1} name={'common/settingLight'} w={'14px'} />
{t('common.More settings')}
</Flex>
)}
</Flex>
{selectSimpleTemplate.systemForm.aiSettings?.model && (
<Flex alignItems={'center'} mt={5}>
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
<Box flex={'1 0 0'}>
<SelectAiModel
width={'100%'}
value={getValues(`aiSettings.model`)}
list={chatModelSelectList}
onchange={(val: any) => {
setValue('aiSettings.model', val);
const maxToken =
llmModelList.find((item) => item.model === getValues('aiSettings.model'))
?.maxResponse || 4000;
const token = maxToken / 2;
setValue('aiSettings.maxToken', token);
setRefresh(!refresh);
}}
/>
</Box>
</Flex>
)}
{selectSimpleTemplate.systemForm.aiSettings?.systemPrompt && (
<Flex mt={10} alignItems={'flex-start'}>
<Box {...LabelStyles}>
{t('core.ai.Prompt')}
<MyTooltip label={t(chatNodeSystemPromptTip)} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
</MyTooltip>
</Box>
{isInitd && (
<PromptEditor
value={aiSystemPrompt}
onChange={(text) => {
startTst(() => {
setValue('aiSettings.systemPrompt', text);
});
}}
variables={formatVariables}
placeholder={t('core.app.tip.chatNodeSystemPromptTip')}
title={t('core.ai.Prompt')}
/>
)}
</Flex>
)}
</Box>
)}
{/* dataset */}
{selectSimpleTemplate?.systemForm?.dataset && (
<Box {...BoxStyles}>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={1}>
<MyIcon name={'core/app/simpleMode/dataset'} w={'20px'} />
<Box ml={2}>{t('core.dataset.Choose Dataset')}</Box>
</Flex>
{selectSimpleTemplate.systemForm.dataset.datasets && (
<Flex alignItems={'center'} {...BoxBtnStyles} onClick={onOpenKbSelect}>
<SmallAddIcon />
{t('common.Choose')}
</Flex>
)}
{(selectSimpleTemplate.systemForm.dataset.limit ||
selectSimpleTemplate.systemForm.dataset.searchMode ||
selectSimpleTemplate.systemForm.dataset.searchEmptyText ||
selectSimpleTemplate.systemForm.dataset.similarity) && (
<Flex
alignItems={'center'}
ml={3}
{...BoxBtnStyles}
onClick={onOpenDatasetParams}
>
<MyIcon name={'edit'} w={'14px'} mr={1} />
{t('common.Params')}
</Flex>
)}
</Flex>
{getValues('dataset.datasets').length > 0 && (
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
{t('core.dataset.search.search mode')}: {datasetSearchMode}
{', '}
{reRankModelList.length > 0 && (
<>
{t('core.dataset.search.ReRank')}:{' '}
{getValues('dataset.usingReRank') ? '✅' : '✖'}
</>
)}
{', '}
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
{', '}
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
{getValues('dataset.searchEmptyText') === ''
? ''
: t('core.dataset.Set Empty Result Tip')}
</Flex>
)}
<Grid
gridTemplateColumns={['repeat(2, minmax(0, 1fr))', 'repeat(3, minmax(0, 1fr))']}
gridGap={[2, 4]}
>
{selectDatasets.map((item) => (
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
<Flex
overflow={'hidden'}
alignItems={'center'}
p={2}
bg={'white'}
boxShadow={
'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'
}
borderRadius={'md'}
border={theme.borders.base}
cursor={'pointer'}
onClick={() =>
router.push({
pathname: '/dataset/detail',
query: {
datasetId: item._id
}
})
}
>
<Avatar src={item.avatar} w={'18px'} mr={1} />
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
{item.name}
</Box>
</Flex>
</MyTooltip>
))}
</Grid>
</Box>
)}
{/* cfr */}
{selectSimpleTemplate?.systemForm?.cfr && getValues('dataset.datasets').length > 0 && (
<Flex {...BoxStyles} alignItems={'center'}>
<Image src={'/imgs/module/cfr.svg'} alt={''} w={'18px'} />
<Box ml={2}>{t('core.module.template.cfr')}</Box>
<MyTooltip label={t('core.module.template.cfr intro')} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
</MyTooltip>
<Box flex={1} />
<Flex {...BoxBtnStyles} onClick={onOpenCfrModal}>
{getValues('cfr.background') === 'none' ? t('common.Not open') : t('common.Opened')}
<Box {...BoxStyles}>
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/ai'} w={'20px'} />
<Box ml={2} flex={1}>
{t('app.AI Settings')}
</Box>
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
<MyIcon mr={1} name={'common/settingLight'} w={'14px'} />
{t('common.More settings')}
</Flex>
</Flex>
)}
<Flex alignItems={'center'} mt={5}>
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
<Box flex={'1 0 0'}>
<SelectAiModel
width={'100%'}
value={getValues(`aiSettings.model`)}
list={chatModelSelectList}
onchange={(val: any) => {
setValue('aiSettings.model', val);
const maxToken =
llmModelList.find((item) => item.model === getValues('aiSettings.model'))
?.maxResponse || 4000;
const token = maxToken / 2;
setValue('aiSettings.maxToken', token);
setRefresh(!refresh);
}}
/>
</Box>
</Flex>
<Flex mt={10} alignItems={'flex-start'}>
<Box {...LabelStyles}>
{t('core.ai.Prompt')}
<MyTooltip label={t(chatNodeSystemPromptTip)} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
</MyTooltip>
</Box>
{isInitd && (
<PromptEditor
value={aiSystemPrompt}
onChange={(text) => {
startTst(() => {
setValue('aiSettings.systemPrompt', text);
});
}}
variables={formatVariables}
placeholder={t('core.app.tip.chatNodeSystemPromptTip')}
title={t('core.ai.Prompt')}
/>
)}
</Flex>
</Box>
{/* dataset */}
<Box {...BoxStyles}>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={1}>
<MyIcon name={'core/app/simpleMode/dataset'} w={'20px'} />
<Box ml={2}>{t('core.dataset.Choose Dataset')}</Box>
</Flex>
<Flex alignItems={'center'} {...BoxBtnStyles} onClick={onOpenKbSelect}>
<SmallAddIcon />
{t('common.Choose')}
</Flex>
<Flex alignItems={'center'} ml={3} {...BoxBtnStyles} onClick={onOpenDatasetParams}>
<MyIcon name={'edit'} w={'14px'} mr={1} />
{t('common.Params')}
</Flex>
</Flex>
{getValues('dataset.datasets').length > 0 && (
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
{t('core.dataset.search.search mode')}: {datasetSearchMode}
{', '}
{reRankModelList.length > 0 && (
<>
{t('core.dataset.search.ReRank')}:{' '}
{getValues('dataset.usingReRank') ? '✅' : '✖'}
</>
)}
{', '}
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
{', '}
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
{getValues('dataset.searchEmptyText') === ''
? ''
: t('core.dataset.Set Empty Result Tip')}
</Flex>
)}
<Grid
gridTemplateColumns={['repeat(2, minmax(0, 1fr))', 'repeat(3, minmax(0, 1fr))']}
gridGap={[2, 4]}
>
{selectDatasets.map((item) => (
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
<Flex
overflow={'hidden'}
alignItems={'center'}
p={2}
bg={'white'}
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
borderRadius={'md'}
border={theme.borders.base}
cursor={'pointer'}
onClick={() =>
router.push({
pathname: '/dataset/detail',
query: {
datasetId: item._id
}
})
}
>
<Avatar src={item.avatar} w={'18px'} mr={1} />
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
{item.name}
</Box>
</Flex>
</MyTooltip>
))}
</Grid>
</Box>
{/* variable */}
{selectSimpleTemplate?.systemForm?.userGuide?.variables && (
<Box {...BoxStyles}>
<VariableEdit
variables={variables}
onChange={(e) => {
setValue('userGuide.variables', e);
setRefresh(!refresh);
}}
/>
</Box>
)}
<Box {...BoxStyles}>
<VariableEdit
variables={variables}
onChange={(e) => {
setValue('userGuide.variables', e);
setRefresh(!refresh);
}}
/>
</Box>
{/* welcome */}
{selectSimpleTemplate?.systemForm?.userGuide?.welcomeText && (
<Box {...BoxStyles}>
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/chat'} w={'20px'} />
<Box mx={2}>{t('core.app.Welcome Text')}</Box>
<MyTooltip label={t(welcomeTextTip)} forceShow>
<QuestionOutlineIcon />
</MyTooltip>
</Flex>
<MyTextarea
mt={2}
bg={'myWhite.400'}
rows={5}
placeholder={t(welcomeTextTip)}
defaultValue={getValues('userGuide.welcomeText')}
onBlur={(e) => {
setValue('userGuide.welcomeText', e.target.value || '');
}}
/>
</Box>
)}
<Box {...BoxStyles}>
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/chat'} w={'20px'} />
<Box mx={2}>{t('core.app.Welcome Text')}</Box>
<MyTooltip label={t(welcomeTextTip)} forceShow>
<QuestionOutlineIcon />
</MyTooltip>
</Flex>
<MyTextarea
mt={2}
bg={'myWhite.400'}
rows={5}
placeholder={t(welcomeTextTip)}
defaultValue={getValues('userGuide.welcomeText')}
onBlur={(e) => {
setValue('userGuide.welcomeText', e.target.value || '');
}}
/>
</Box>
{/* tts */}
{selectSimpleTemplate?.systemForm?.userGuide?.tts && (
<Box {...BoxStyles}>
<TTSSelect
value={getValues('userGuide.tts')}
onChange={(e) => {
setValue('userGuide.tts', e);
setRefresh((state) => !state);
}}
/>
</Box>
)}
<Box {...BoxStyles}>
<TTSSelect
value={getValues('userGuide.tts')}
onChange={(e) => {
setValue('userGuide.tts', e);
setRefresh((state) => !state);
}}
/>
</Box>
{/* question guide */}
{selectSimpleTemplate?.systemForm?.userGuide?.questionGuide && (
<Box {...BoxStyles} borderBottom={'none'}>
<QGSwitch
isChecked={getValues('userGuide.questionGuide')}
size={'lg'}
onChange={(e) => {
const value = e.target.checked;
setValue('userGuide.questionGuide', value);
setRefresh((state) => !state);
}}
/>
</Box>
)}
<Box {...BoxStyles} borderBottom={'none'}>
<QGSwitch
isChecked={getValues('userGuide.questionGuide')}
size={'lg'}
onChange={(e) => {
const value = e.target.checked;
setValue('userGuide.questionGuide', value);
setRefresh((state) => !state);
}}
/>
</Box>
</Box>
</Box>
@@ -491,7 +427,6 @@ const EditForm = ({
onCloseAIChatSetting();
}}
defaultData={getValues('aiSettings')}
simpleModeTemplate={selectSimpleTemplate}
pickerMenu={formatVariables}
/>
)}
@@ -508,28 +443,7 @@ const EditForm = ({
)}
{isOpenDatasetParams && (
<DatasetParamsModal
// {...getValues('dataset')}
searchMode={getValues('dataset.searchMode')}
searchEmptyText={
selectSimpleTemplate?.systemForm?.dataset?.searchEmptyText
? getValues('dataset.searchEmptyText')
: undefined
}
limit={
selectSimpleTemplate?.systemForm?.dataset?.limit
? getValues('dataset.limit')
: undefined
}
similarity={
selectSimpleTemplate?.systemForm?.dataset?.similarity
? getValues('dataset.similarity')
: undefined
}
usingReRank={
selectSimpleTemplate?.systemForm?.dataset?.usingReRank
? getValues('dataset.usingReRank')
: undefined
}
{...datasetSearchSetting}
maxTokens={tokenLimit}
onClose={onCloseDatasetParams}
onSuccess={(e) => {
@@ -542,15 +456,6 @@ const EditForm = ({
}}
/>
)}
{isOpenCfrModal && (
<CfrEditModal
onClose={onCloseCfrModal}
defaultValue={getValues('cfr.background')}
onFinish={(e) => {
setValue('cfr.background', e);
}}
/>
)}
</Box>
);
};

View File

@@ -39,6 +39,8 @@ import { fileDownload } from '@/web/common/file/utils';
import { readCsvContent } from '@fastgpt/web/common/file/read/csv';
import { delay } from '@fastgpt/global/common/system/utils';
import QuoteItem from '@/components/core/dataset/QuoteItem';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
@@ -48,9 +50,13 @@ type FormType = {
inputText: string;
searchParams: {
searchMode: `${DatasetSearchModeEnum}`;
usingReRank: boolean;
limit: number;
similarity: number;
similarity?: number;
limit?: number;
usingReRank?: boolean;
searchEmptyText?: string;
datasetSearchUsingExtensionQuery?: boolean;
datasetSearchExtensionModel?: string;
datasetSearchExtensionBg?: string;
};
};
@@ -58,6 +64,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
const { t } = useTranslation();
const theme = useTheme();
const { toast } = useToast();
const { llmModelList } = useSystemStore();
const { datasetDetail } = useDatasetStore();
const { pushDatasetTestItem } = useSearchTestStore();
const [inputType, setInputType] = useState<'text' | 'file'>('text');
@@ -77,12 +84,15 @@ const Test = ({ datasetId }: { datasetId: string }) => {
searchMode: DatasetSearchModeEnum.embedding,
usingReRank: false,
limit: 5000,
similarity: 0
similarity: 0,
datasetSearchUsingExtensionQuery: false,
datasetSearchExtensionModel: llmModelList[0].model,
datasetSearchExtensionBg: ''
}
}
});
const searchModeData = DatasetSearchModeMap[getValues('searchParams.searchMode')];
const searchModeData = DatasetSearchModeMap[getValues(`searchParams.searchMode`)];
const {
isOpen: isOpenSelectMode,
@@ -123,34 +133,34 @@ const Test = ({ datasetId }: { datasetId: string }) => {
});
}
});
const { mutate: onFileTest, isLoading: fileTestIsLoading } = useRequest({
mutationFn: async ({ searchParams }: FormType) => {
if (!selectFile) return Promise.reject('File is not selected');
const { data } = await readCsvContent({ file: selectFile });
const testList = data.slice(0, 100);
const results: SearchTestResponse[] = [];
// const { mutate: onFileTest, isLoading: fileTestIsLoading } = useRequest({
// mutationFn: async ({ searchParams }: FormType) => {
// if (!selectFile) return Promise.reject('File is not selected');
// const { data } = await readCsvContent({ file: selectFile });
// const testList = data.slice(0, 100);
// const results: SearchTestResponse[] = [];
for await (const item of testList) {
try {
const result = await postSearchText({ datasetId, text: item[0].trim(), ...searchParams });
results.push(result);
} catch (error) {
await delay(500);
}
}
// for await (const item of testList) {
// try {
// const result = await postSearchText({ datasetId, text: item[0].trim(), ...searchParams });
// results.push(result);
// } catch (error) {
// await delay(500);
// }
// }
return results;
},
onSuccess(res: SearchTestResponse[]) {
console.log(res);
},
onError(err) {
toast({
title: getErrText(err),
status: 'error'
});
}
});
// return results;
// },
// onSuccess(res: SearchTestResponse[]) {
// console.log(res);
// },
// onError(err) {
// toast({
// title: getErrText(err),
// status: 'error'
// });
// }
// });
const onSelectFile = async (files: File[]) => {
const file = files[0];
@@ -295,13 +305,13 @@ const Test = ({ datasetId }: { datasetId: string }) => {
<Flex justifyContent={'flex-end'}>
<Button
size={'sm'}
isLoading={textTestIsLoading || fileTestIsLoading}
isLoading={textTestIsLoading}
isDisabled={inputType === 'file' && !selectFile}
onClick={() => {
if (inputType === 'text') {
handleSubmit((data) => onTextTest(data))();
} else {
handleSubmit((data) => onFileTest(data))();
// handleSubmit((data) => onFileTest(data))();
}
}}
>