v4.6.2-alpah (#511)

This commit is contained in:
Archer
2023-11-24 15:29:43 +08:00
committed by GitHub
parent 60f752629f
commit 9cb4280a16
208 changed files with 5396 additions and 3500 deletions

View File

@@ -1,10 +1,10 @@
import { TaskResponseKeyEnum } from '@fastgpt/global/core/chat/constants';
import { sseResponseEventEnum } from '@fastgpt/service/common/response/constant';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { parseStreamChunk, SSEParseData } from '@/utils/sse';
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/api.d';
import { StartChatFnProps } from '@/components/ChatBox';
import { getToken } from '@/web/support/user/auth';
import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
type StreamFetchProps = {
url?: string;
@@ -12,16 +12,17 @@ type StreamFetchProps = {
onMessage: StartChatFnProps['generatingMessage'];
abortSignal: AbortController;
};
type StreamResponseType = {
responseText: string;
[ModuleOutputKeyEnum.responseData]: ChatHistoryItemResType[];
};
export const streamFetch = ({
url = '/api/v1/chat/completions',
data,
onMessage,
abortSignal
}: StreamFetchProps) =>
new Promise<{
responseText: string;
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType[];
}>(async (resolve, reject) => {
new Promise<StreamResponseType>(async (resolve, reject) => {
try {
const response = await window.fetch(url, {
method: 'POST',

View File

@@ -28,6 +28,16 @@ export const readTxtContent = (file: File) => {
*/
export const readPdfContent = (file: File) =>
new Promise<string>((resolve, reject) => {
type TokenType = {
str: string;
dir: string;
width: number;
height: number;
transform: number[];
fontName: string;
hasEOL: boolean;
};
try {
const pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.workerSrc = '/js/pdf.worker.js';
@@ -36,9 +46,19 @@ export const readPdfContent = (file: File) =>
const page = await doc.getPage(pageNo);
const tokenizedText = await page.getTextContent();
const viewport = page.getViewport({ scale: 1 });
const pageHeight = viewport.height;
const headerThreshold = pageHeight * 0.07; // 假设页头在页面顶部5%的区域内
const footerThreshold = pageHeight * 0.93; // 假设页脚在页面底部5%的区域内
const pageText = tokenizedText.items
.map((token: any) => token.str)
.filter((item: string) => item)
.filter((token: TokenType) => {
return (
!token.transform ||
(token.transform[5] > headerThreshold && token.transform[5] < footerThreshold)
);
})
.map((token: TokenType) => token.str)
.join('');
return pageText;
};
@@ -54,7 +74,7 @@ export const readPdfContent = (file: File) =>
pageTextPromises.push(readPDFPage(doc, pageNo));
}
const pageTexts = await Promise.all(pageTextPromises);
resolve(pageTexts.join('\n'));
resolve(pageTexts.join(''));
} catch (err) {
console.log(err, 'pdf load error');
reject('解析 PDF 失败');

View File

@@ -51,7 +51,7 @@ export const useEditTitle = ({
// eslint-disable-next-line react/display-name
const EditModal = useCallback(
({ maxLength = 30 }: { maxLength?: number }) => (
<MyModal isOpen={isOpen} onClose={onClose} title={title}>
<MyModal isOpen={isOpen} onClose={onClose} iconSrc="/imgs/modal/edit.svg" title={title}>
<ModalBody>
{!!tip && (
<Box mb={2} color={'myGray.500'} fontSize={'sm'}>

View File

@@ -11,6 +11,7 @@ import {
defaultVectorModels,
defaultAudioSpeechModels
} from '@fastgpt/global/core/ai/model';
import { AppSimpleEditConfigTemplateType } from '@fastgpt/global/core/app/type';
export let feConfigs: FeConfigsType = {};
export let priceMd = '';
@@ -23,6 +24,7 @@ export let cqModelList = defaultCQModels;
export let extractModelList = defaultExtractModels;
export let qgModelList = defaultQGModels;
export let audioSpeechModels = defaultAudioSpeechModels;
export let simpleModeTemplates: AppSimpleEditConfigTemplateType[] = [];
let retryTimes = 3;
@@ -43,6 +45,8 @@ export const clientInitData = async (): Promise<InitDateResponse> => {
priceMd = res.priceMd;
systemVersion = res.systemVersion;
simpleModeTemplates = res.simpleModeTemplates;
return res;
} catch (error) {
retryTimes--;

View File

@@ -1,7 +1,7 @@
import { useState, useCallback, useEffect, useMemo, useRef } from 'react';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { AppTTSConfigType } from '@/types/app';
import type { AppTTSConfigType } from '@fastgpt/global/core/module/type.d';
import { TTSTypeEnum } from '@/constants/app';
import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';

View File

@@ -1,602 +0,0 @@
import type { AppTTSConfigType, VariableItemType } from '@/types/app';
import { chatModelList } from '@/web/common/system/staticData';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import {
FlowNodeInputTypeEnum,
FlowNodeTypeEnum,
FlowNodeValTypeEnum,
FlowNodeSpecialInputKeyEnum
} from '@fastgpt/global/core/module/node/constant';
import { SystemInputEnum } from '@/constants/app';
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type.d';
import type { AIChatProps } from '@/types/core/aiChat';
import { getGuideModule, splitGuideModule } from '@/global/core/app/modules/utils';
export type EditFormType = {
chatModel: AIChatProps;
dataset: {
list: SelectedDatasetType;
searchSimilarity: number;
searchLimit: number;
searchEmptyText: string;
rerank: boolean;
};
guide: {
welcome: {
text: string;
};
};
variables: VariableItemType[];
questionGuide: boolean;
tts: AppTTSConfigType;
};
export const getDefaultAppForm = (): EditFormType => {
const defaultChatModel = chatModelList[0];
return {
chatModel: {
model: defaultChatModel?.model,
systemPrompt: '',
temperature: 0,
[SystemInputEnum.isResponseAnswerText]: true,
quotePrompt: '',
quoteTemplate: '',
maxToken: defaultChatModel ? defaultChatModel.maxResponse / 2 : 4000,
frequency: 0.5,
presence: -0.5
},
dataset: {
list: [],
searchSimilarity: 0.4,
searchLimit: 5,
searchEmptyText: '',
rerank: false
},
guide: {
welcome: {
text: ''
}
},
variables: [],
questionGuide: false,
tts: {
type: 'web'
}
};
};
export const appModules2Form = (modules: ModuleItemType[]) => {
const defaultAppForm = getDefaultAppForm();
const updateVal = ({
formKey,
inputs,
key
}: {
formKey: string;
inputs: FlowNodeInputItemType[];
key: string;
}) => {
const propertyPath = formKey.split('.');
let currentObj: any = defaultAppForm;
for (let i = 0; i < propertyPath.length - 1; i++) {
currentObj = currentObj[propertyPath[i]];
}
const val =
inputs.find((item) => item.key === key)?.value ||
currentObj[propertyPath[propertyPath.length - 1]];
currentObj[propertyPath[propertyPath.length - 1]] = val;
};
modules.forEach((module) => {
if (module.flowType === FlowNodeTypeEnum.chatNode) {
updateVal({
formKey: 'chatModel.model',
inputs: module.inputs,
key: 'model'
});
updateVal({
formKey: 'chatModel.temperature',
inputs: module.inputs,
key: 'temperature'
});
updateVal({
formKey: 'chatModel.maxToken',
inputs: module.inputs,
key: 'maxToken'
});
updateVal({
formKey: 'chatModel.systemPrompt',
inputs: module.inputs,
key: 'systemPrompt'
});
updateVal({
formKey: 'chatModel.quoteTemplate',
inputs: module.inputs,
key: 'quoteTemplate'
});
updateVal({
formKey: 'chatModel.quotePrompt',
inputs: module.inputs,
key: 'quotePrompt'
});
} else if (module.flowType === FlowNodeTypeEnum.datasetSearchNode) {
updateVal({
formKey: 'dataset.list',
inputs: module.inputs,
key: 'datasets'
});
updateVal({
formKey: 'dataset.searchSimilarity',
inputs: module.inputs,
key: 'similarity'
});
updateVal({
formKey: 'dataset.searchLimit',
inputs: module.inputs,
key: 'limit'
});
updateVal({
formKey: 'dataset.rerank',
inputs: module.inputs,
key: 'rerank'
});
// empty text
const emptyOutputs = module.outputs.find((item) => item.key === 'isEmpty')?.targets || [];
const emptyOutput = emptyOutputs[0];
if (emptyOutput) {
const target = modules.find((item) => item.moduleId === emptyOutput.moduleId);
defaultAppForm.dataset.searchEmptyText =
target?.inputs?.find((item) => item.key === FlowNodeSpecialInputKeyEnum.answerText)
?.value || '';
}
} else if (module.flowType === FlowNodeTypeEnum.userGuide) {
const { welcomeText, variableModules, questionGuide, ttsConfig } = splitGuideModule(
getGuideModule(modules)
);
if (welcomeText) {
defaultAppForm.guide.welcome = {
text: welcomeText
};
}
defaultAppForm.variables = variableModules;
defaultAppForm.questionGuide = !!questionGuide;
defaultAppForm.tts = ttsConfig;
}
});
return defaultAppForm;
};
const chatModelInput = (formData: EditFormType): FlowNodeInputItemType[] => [
{
key: 'model',
value: formData.chatModel.model,
type: 'custom',
label: '对话模型',
connected: true
},
{
key: 'temperature',
value: formData.chatModel.temperature,
type: 'slider',
label: '温度',
connected: true
},
{
key: 'maxToken',
value: formData.chatModel.maxToken,
type: 'custom',
label: '回复上限',
connected: true
},
{
key: 'systemPrompt',
value: formData.chatModel.systemPrompt || '',
type: 'textarea',
label: '系统提示词',
connected: true
},
{
key: SystemInputEnum.isResponseAnswerText,
value: true,
type: 'hidden',
label: '返回AI内容',
connected: true
},
{
key: 'quoteTemplate',
value: formData.chatModel.quoteTemplate || '',
type: 'hidden',
label: '引用内容模板',
connected: true
},
{
key: 'quotePrompt',
value: formData.chatModel.quotePrompt || '',
type: 'hidden',
label: '引用内容提示词',
connected: true
},
{
key: 'switch',
type: 'target',
label: '触发器',
connected: formData.dataset.list.length > 0 && !!formData.dataset.searchEmptyText
},
{
key: 'quoteQA',
type: 'target',
label: '引用内容',
connected: formData.dataset.list.length > 0
},
{
key: 'history',
type: 'target',
label: '聊天记录',
connected: true
},
{
key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true
}
];
const userGuideTemplate = (formData: EditFormType): ModuleItemType[] => [
{
name: '用户引导',
flowType: FlowNodeTypeEnum.userGuide,
inputs: [
{
key: SystemInputEnum.welcomeText,
type: FlowNodeInputTypeEnum.hidden,
label: '开场白',
value: formData.guide.welcome.text
},
{
key: SystemInputEnum.variables,
type: FlowNodeInputTypeEnum.hidden,
label: '对话框变量',
value: formData.variables
},
{
key: SystemInputEnum.questionGuide,
type: FlowNodeInputTypeEnum.hidden,
label: '问题引导',
value: formData.questionGuide
},
{
key: SystemInputEnum.tts,
type: FlowNodeInputTypeEnum.hidden,
label: '语音播报',
value: formData.tts
}
],
outputs: [],
position: {
x: 447.98520778293346,
y: 721.4016845336229
},
moduleId: 'userGuide'
}
];
const simpleChatTemplate = (formData: EditFormType): ModuleItemType[] => [
{
name: '用户问题(对话入口)',
flowType: FlowNodeTypeEnum.questionInput,
inputs: [
{
key: 'userChatInput',
connected: true,
label: '用户问题',
type: 'target'
}
],
outputs: [
{
key: 'userChatInput',
targets: [
{
moduleId: 'chatModule',
key: 'userChatInput'
}
]
}
],
position: {
x: 464.32198615344566,
y: 1602.2698463081606
},
moduleId: 'userChatInput'
},
{
name: '聊天记录',
flowType: FlowNodeTypeEnum.historyNode,
inputs: [
{
key: 'maxContext',
value: 6,
connected: true,
type: 'numberInput',
label: '最长记录数'
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true
}
],
outputs: [
{
key: 'history',
targets: [
{
moduleId: 'chatModule',
key: 'history'
}
]
}
],
position: {
x: 452.5466249541586,
y: 1276.3930310334215
},
moduleId: 'history'
},
{
name: 'AI 对话',
flowType: FlowNodeTypeEnum.chatNode,
inputs: chatModelInput(formData),
showStatus: true,
outputs: [
{
key: 'answerText',
label: 'AI回复',
description: '直接响应,无需配置',
type: 'hidden',
targets: []
},
{
key: 'finish',
label: '回复结束',
description: 'AI 回复完成后触发',
valueType: 'boolean',
type: 'source',
targets: []
}
],
position: {
x: 981.9682828103937,
y: 890.014595014464
},
moduleId: 'chatModule'
}
];
const kbTemplate = (formData: EditFormType): ModuleItemType[] => [
{
name: '用户问题(对话入口)',
flowType: FlowNodeTypeEnum.questionInput,
inputs: [
{
key: 'userChatInput',
label: '用户问题',
type: 'target',
connected: true
}
],
outputs: [
{
key: 'userChatInput',
targets: [
{
moduleId: 'chatModule',
key: 'userChatInput'
},
{
moduleId: 'datasetSearch',
key: 'userChatInput'
}
]
}
],
position: {
x: 464.32198615344566,
y: 1602.2698463081606
},
moduleId: 'userChatInput'
},
{
name: '聊天记录',
flowType: FlowNodeTypeEnum.historyNode,
inputs: [
{
key: 'maxContext',
value: 6,
connected: true,
type: 'numberInput',
label: '最长记录数'
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true
}
],
outputs: [
{
key: 'history',
targets: [
{
moduleId: 'chatModule',
key: 'history'
}
]
}
],
position: {
x: 452.5466249541586,
y: 1276.3930310334215
},
moduleId: 'history'
},
{
name: '知识库搜索',
flowType: FlowNodeTypeEnum.datasetSearchNode,
showStatus: true,
inputs: [
{
key: 'datasets',
value: formData.dataset.list,
type: FlowNodeInputTypeEnum.custom,
label: '关联的知识库',
connected: true
},
{
key: 'similarity',
value: formData.dataset.searchSimilarity,
type: FlowNodeInputTypeEnum.slider,
label: '相似度',
connected: true
},
{
key: 'limit',
value: formData.dataset.searchLimit,
type: FlowNodeInputTypeEnum.slider,
label: '单次搜索上限',
connected: true
},
{
key: 'switch',
type: FlowNodeInputTypeEnum.target,
label: '触发器',
connected: false
},
{
key: 'userChatInput',
type: FlowNodeInputTypeEnum.target,
label: '用户问题',
connected: true
},
{
key: 'rerank',
type: FlowNodeInputTypeEnum.switch,
label: '结果重排',
description: '将召回的结果进行进一步重排,可增加召回率',
plusField: true,
connected: true,
value: formData.dataset.rerank
}
],
outputs: [
{
key: 'isEmpty',
targets: formData.dataset.searchEmptyText
? [
{
moduleId: 'emptyText',
key: 'switch'
}
]
: []
},
{
key: 'unEmpty',
targets: formData.dataset.searchEmptyText
? [
{
moduleId: 'chatModule',
key: 'switch'
}
]
: []
},
{
key: 'quoteQA',
targets: [
{
moduleId: 'chatModule',
key: 'quoteQA'
}
]
}
],
position: {
x: 956.0838440206068,
y: 887.462827870246
},
moduleId: 'datasetSearch'
},
...(formData.dataset.searchEmptyText
? [
{
name: '指定回复',
flowType: FlowNodeTypeEnum.answerNode,
inputs: [
{
key: 'switch',
type: FlowNodeInputTypeEnum.target,
label: '触发器',
connected: true
},
{
key: FlowNodeSpecialInputKeyEnum.answerText,
value: formData.dataset.searchEmptyText,
type: FlowNodeInputTypeEnum.textarea,
valueType: FlowNodeValTypeEnum.string,
label: '回复的内容',
connected: true
}
],
outputs: [],
position: {
x: 1553.5815811529146,
y: 637.8753731306779
},
moduleId: 'emptyText'
}
]
: []),
{
name: 'AI 对话',
flowType: FlowNodeTypeEnum.chatNode,
inputs: chatModelInput(formData),
showStatus: true,
outputs: [
{
key: 'answerText',
label: 'AI回复',
description: '直接响应,无需配置',
type: 'hidden',
targets: []
},
{
key: 'finish',
label: '回复结束',
description: 'AI 回复完成后触发',
valueType: 'boolean',
type: 'source',
targets: []
}
],
position: {
x: 1551.71405495818,
y: 977.4911578918461
},
moduleId: 'chatModule'
}
];
export const appForm2Modules = (formData: EditFormType) => {
const modules = [
...userGuideTemplate(formData),
...(formData.dataset.list.length > 0 ? kbTemplate(formData) : simpleChatTemplate(formData))
];
return modules as ModuleItemType[];
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
import { ModuleItemType } from '@fastgpt/global/core/module/type';
import { POST } from '@/web/common/api/request';
import { chatModelList } from '@/web/common/system/staticData';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import type { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api.d';
export async function postForm2Modules(
data: AppSimpleEditFormType,
templateId = 'fastgpt-universal'
) {
function userGuideTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
return [
{
name: '用户引导',
flowType: FlowNodeTypeEnum.userGuide,
inputs: [
{
key: ModuleInputKeyEnum.welcomeText,
type: FlowNodeInputTypeEnum.hidden,
label: '开场白',
value: formData.userGuide.welcomeText
},
{
key: ModuleInputKeyEnum.variables,
type: FlowNodeInputTypeEnum.hidden,
label: '对话框变量',
value: formData.userGuide.variables
},
{
key: ModuleInputKeyEnum.questionGuide,
type: FlowNodeInputTypeEnum.hidden,
label: '问题引导',
value: formData.userGuide.questionGuide
},
{
key: ModuleInputKeyEnum.tts,
type: FlowNodeInputTypeEnum.hidden,
label: '语音播报',
value: formData.userGuide.tts
}
],
outputs: [],
position: {
x: 447.98520778293346,
y: 721.4016845336229
},
moduleId: 'userGuide'
}
];
}
const maxToken =
chatModelList.find((item) => item.model === data.aiSettings.model)?.maxResponse || 4000;
const props: FormatForm2ModulesProps = {
formData: data,
chatModelMaxToken: maxToken,
chatModelList
};
const modules = await POST<ModuleItemType[]>(`/core/app/form2Modules/${templateId}`, props);
return [...userGuideTemplate(data), ...modules];
}

View File

@@ -104,98 +104,99 @@ const SelectCollections = ({
w={'100%'}
h={['90vh', '80vh']}
isCentered
iconSrc="/imgs/modal/move.svg"
title={
<Box>
<ParentPaths
paths={paths.map((path, i) => ({
parentId: path.parentId,
parentName: path.parentName
}))}
FirstPathDom={
<>
<Box fontWeight={'bold'} fontSize={['sm', 'lg']}>
{title || type === 'folder'
? t('common.Select One Folder')
: t('dataset.collections.Select Collection')}
</Box>
{!!tip && (
<Box fontSize={'sm'} color={'myGray.500'}>
{tip}
</Box>
)}
</>
}
onClick={(e) => {
setParentId(e);
}}
/>
</Box>
}
>
<Flex flexDirection={'column'} flex={'1 0 0'}>
<Box flex={'1 0 0'} px={4} py={2}>
<Flex flexDirection={'column'} h={'100%'} position={'relative'}>
<Box>
<ParentPaths
paths={paths.map((path, i) => ({
parentId: path.parentId,
parentName: path.parentName
}))}
FirstPathDom={
<>
<Box fontWeight={'bold'} fontSize={['sm', 'lg']}>
{title || type === 'folder'
? t('common.Select One Folder')
: t('dataset.collections.Select Collection')}
</Box>
{!!tip && (
<Box fontSize={'sm'} color={'myGray.500'}>
{tip}
<Box flex={'1 0 0'} px={4} py={2} position={'relative'}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
overflowY={'auto'}
mt={2}
>
{collections.map((item) =>
(() => {
const selected = selectedDatasetCollectionIds.includes(item._id);
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
{...(selected
? {
bg: 'myBlue.300'
}
: {})}
onClick={() => {
if (item.type === DatasetCollectionTypeEnum.folder) {
setParentId(item._id);
} else {
let result: string[] = [];
if (max === 1) {
result = [item._id];
} else if (selected) {
result = selectedDatasetCollectionIds.filter((id) => id !== item._id);
} else if (selectedDatasetCollectionIds.length < max) {
result = [...selectedDatasetCollectionIds, item._id];
}
setSelectedDatasetCollectionIds(result);
onChange && onChange({ parentId, collectionIds: result });
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Image src={item.icon} w={'18px'} alt={''} />
<Box ml={3} fontSize={'sm'}>
{item.name}
</Box>
)}
</>
}
onClick={(e) => {
setParentId(e);
}}
/>
</Box>
<Box flex={'1 0 0'} overflowY={'auto'} mt={2}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
>
{collections.map((item) =>
(() => {
const selected = selectedDatasetCollectionIds.includes(item._id);
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
{...(selected
? {
bg: 'myBlue.300'
}
: {})}
onClick={() => {
if (item.type === DatasetCollectionTypeEnum.folder) {
setParentId(item._id);
} else {
let result: string[] = [];
if (max === 1) {
result = [item._id];
} else if (selected) {
result = selectedDatasetCollectionIds.filter((id) => id !== item._id);
} else if (selectedDatasetCollectionIds.length < max) {
result = [...selectedDatasetCollectionIds, item._id];
}
setSelectedDatasetCollectionIds(result);
onChange && onChange({ parentId, collectionIds: result });
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Image src={item.icon} w={'18px'} alt={''} />
<Box ml={3} fontSize={'sm'}>
{item.name}
</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{collections.length === 0 && (
<Flex mt={'10vh'} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
{t('common.folder.No Folder')}
</Box>
</Flex>
)}
</Box>
<Loading loading={isLoading} fixed={false} />
</Flex>
</Flex>
</Card>
);
})()
)}
</Grid>
{collections.length === 0 && (
<Flex mt={'20vh'} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
{t('common.folder.No Folder')}
</Box>
</Flex>
)}
<Loading loading={isLoading} fixed={false} />
</Box>
{CustomFooter ? (
<>{CustomFooter}</>

View File

@@ -0,0 +1,82 @@
import type { BoxProps } from '@chakra-ui/react';
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants';
export const FlowValueTypeStyle: Record<`${ModuleDataTypeEnum}`, BoxProps> = {
[ModuleDataTypeEnum.string]: {
background: '#36ADEF'
},
[ModuleDataTypeEnum.number]: {
background: '#FB7C3C'
},
[ModuleDataTypeEnum.boolean]: {
background: '#E7D118'
},
[ModuleDataTypeEnum.chatHistory]: {
background: '#00A9A6'
},
[ModuleDataTypeEnum.datasetQuote]: {
background: '#A558C9'
},
[ModuleDataTypeEnum.any]: {
background: '#9CA2A8'
},
[ModuleDataTypeEnum.selectApp]: {
background: '#6a6efa'
},
[ModuleDataTypeEnum.selectDataset]: {
background: '#21ba45'
}
};
export const FlowValueTypeMap = {
[ModuleDataTypeEnum.string]: {
label: 'core.module.valueType.string',
value: ModuleDataTypeEnum.string,
example: ''
},
[ModuleDataTypeEnum.number]: {
label: 'core.module.valueType.number',
value: ModuleDataTypeEnum.number,
example: ''
},
[ModuleDataTypeEnum.boolean]: {
label: 'core.module.valueType.boolean',
value: ModuleDataTypeEnum.boolean,
example: ''
},
[ModuleDataTypeEnum.chatHistory]: {
label: 'core.module.valueType.chatHistory',
value: ModuleDataTypeEnum.chatHistory,
example: `{
obj: System | Human | AI;
value: string;
}`
},
[ModuleDataTypeEnum.datasetQuote]: {
label: 'core.module.valueType.datasetQuote',
value: ModuleDataTypeEnum.datasetQuote,
example: `{
id: string;
datasetId: string;
collectionId: string;
sourceName: string;
sourceId?: string;
q: string;
a: string
}`
},
[ModuleDataTypeEnum.any]: {
label: 'core.module.valueType.any',
value: ModuleDataTypeEnum.any,
example: ''
},
[ModuleDataTypeEnum.selectApp]: {
label: 'core.module.valueType.selectApp',
value: ModuleDataTypeEnum.selectApp,
example: ''
},
[ModuleDataTypeEnum.selectDataset]: {
label: 'core.module.valueType.selectDataset',
value: ModuleDataTypeEnum.selectDataset,
example: ''
}
};

View File

@@ -0,0 +1,7 @@
export const edgeOptions = {
style: {
strokeWidth: 1.5,
stroke: '#5A646Es'
}
};
export const connectionLineStyle = { strokeWidth: 1.5, stroke: '#5A646Es' };

View File

@@ -0,0 +1,153 @@
import { UserGuideModule } from '@fastgpt/global/core/module/template/system/userGuide';
import { UserInputModule } from '@fastgpt/global/core/module/template/system/userInput';
import { HistoryModule } from '@fastgpt/global/core/module/template/system/history';
import { AiChatModule } from '@fastgpt/global/core/module/template/system/aiChat';
import { DatasetSearchModule } from '@fastgpt/global/core/module/template/system/datasetSearch';
import { AssignedAnswerModule } from '@fastgpt/global/core/module/template/system/assignedAnswer';
import { ClassifyQuestionModule } from '@fastgpt/global/core/module/template/system/classifyQuestion';
import { ContextExtractModule } from '@fastgpt/global/core/module/template/system/contextExtract';
import { HttpModule } from '@fastgpt/global/core/module/template/system/http';
import { EmptyModule } from '@fastgpt/global/core/module/template/system/empty';
import { RunAppModule } from '@fastgpt/global/core/module/template/system/runApp';
import { PluginInputModule } from '@fastgpt/global/core/module/template/system/pluginInput';
import { PluginOutputModule } from '@fastgpt/global/core/module/template/system/pluginOutput';
import { RunPluginModule } from '@fastgpt/global/core/module/template/system/runPlugin';
import type {
FlowModuleTemplateType,
moduleTemplateListType
} from '@fastgpt/global/core/module/type.d';
import { ModuleTemplateTypeEnum } from '@fastgpt/global/core/module/constants';
export const appSystemModuleTemplates: FlowModuleTemplateType[] = [
UserGuideModule,
UserInputModule,
HistoryModule,
AiChatModule,
AssignedAnswerModule,
DatasetSearchModule,
RunAppModule,
ClassifyQuestionModule,
ContextExtractModule,
HttpModule
];
export const pluginSystemModuleTemplates: FlowModuleTemplateType[] = [
PluginInputModule,
PluginOutputModule,
HistoryModule,
AiChatModule,
AssignedAnswerModule,
DatasetSearchModule,
RunAppModule,
ClassifyQuestionModule,
ContextExtractModule,
HttpModule
];
export const moduleTemplatesFlat: FlowModuleTemplateType[] = [
UserGuideModule,
UserInputModule,
HistoryModule,
AiChatModule,
DatasetSearchModule,
AssignedAnswerModule,
ClassifyQuestionModule,
ContextExtractModule,
HttpModule,
EmptyModule,
RunAppModule,
PluginInputModule,
PluginOutputModule,
RunPluginModule
];
export const moduleTemplatesList: moduleTemplateListType = [
{
type: ModuleTemplateTypeEnum.userGuide,
label: '引导模块',
list: []
},
{
type: ModuleTemplateTypeEnum.systemInput,
label: '系统输入',
list: []
},
{
type: ModuleTemplateTypeEnum.textAnswer,
label: '文本输出',
list: []
},
{
type: ModuleTemplateTypeEnum.dataset,
label: '知识库',
list: []
},
{
type: ModuleTemplateTypeEnum.functionCall,
label: '函数调用',
list: []
},
{
type: ModuleTemplateTypeEnum.externalCall,
label: '外部调用',
list: []
},
{
type: ModuleTemplateTypeEnum.personalPlugin,
label: '个人插件',
list: []
},
{
type: ModuleTemplateTypeEnum.communityPlugin,
label: '社区插件',
list: []
},
{
type: ModuleTemplateTypeEnum.commercialPlugin,
label: '商业插件',
list: []
},
{
type: ModuleTemplateTypeEnum.other,
label: '其他',
list: []
}
];
// export const appSystemModuleTemplates = [
// {
// label: '引导模块',
// list: [UserGuideModule]
// },
// {
// label: '输入模块',
// list: [UserInputModule, HistoryModule]
// },
// {
// label: '内容生成',
// list: [AiChatModule, AssignedAnswerModule]
// },
// {
// label: '核心调用',
// list: [DatasetSearchModule, RunAppModule]
// },
// {
// label: '函数模块',
// list: [ClassifyQuestionModule, ContextExtractModule, HttpModule]
// }
// ];
// export const pluginModuleTemplates = [
// {
// label: '输入输出',
// list: [PluginInputModule, PluginOutputModule, HistoryModule]
// },
// {
// label: '内容生成',
// list: [AiChatModule, AssignedAnswerModule]
// },
// {
// label: '核心调用',
// list: [DatasetSearchModule, RunAppModule]
// },
// {
// label: '函数模块',
// list: [ClassifyQuestionModule, ContextExtractModule, HttpModule]
// }
// ];

View File

@@ -11,9 +11,8 @@ export const postCreatePlugin = (data: CreateOnePluginParams) =>
POST<string>('/core/plugin/create', data);
export const putUpdatePlugin = (data: UpdatePluginParams) => PUT('/core/plugin/update', data);
export const getUserPlugins = () => GET<PluginListItemType[]>('/core/plugin/list');
export const getUserPlugs2ModuleTemplates = () =>
GET<FlowModuleTemplateType[]>('/core/plugin/templateList');
export const getPluginModuleDetail = (id: string) =>
GET<FlowModuleTemplateType>('/core/plugin/moduleDetail', { id });
export const getPlugTemplates = () => GET<FlowModuleTemplateType[]>('/core/plugin/templates');
export const getPreviewPluginModule = (id: string) =>
GET<FlowModuleTemplateType>('/core/plugin/getPreviewModule', { id });
export const getOnePlugin = (id: string) => GET<PluginItemSchema>('/core/plugin/detail', { id });
export const delOnePlugin = (id: string) => DELETE('/core/plugin/delete', { id });

View File

@@ -1,23 +1,23 @@
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import type { FlowModuleTemplateType } from '@fastgpt/global/core/module/type';
import { getUserPlugs2ModuleTemplates } from '../api';
import { getPlugTemplates } from '../api';
import { FlowModuleTemplateType } from '@fastgpt/global/core/module/type';
type State = {
pluginModuleTemplates: FlowModuleTemplateType[];
loadPluginModuleTemplates: (init?: boolean) => Promise<FlowModuleTemplateType[]>;
loadPluginTemplates: (init?: boolean) => Promise<FlowModuleTemplateType[]>;
};
export const usePluginStore = create<State>()(
devtools(
immer((set, get) => ({
pluginModuleTemplates: [],
async loadPluginModuleTemplates(init) {
async loadPluginTemplates(init) {
if (!init && get().pluginModuleTemplates.length > 0) {
return get().pluginModuleTemplates;
}
const templates = await getUserPlugs2ModuleTemplates();
const templates = await getPlugTemplates();
set((state) => {
state.pluginModuleTemplates = templates;
});

View File

@@ -4,7 +4,11 @@ import type { ResLogin } from '@/global/support/api/userRes.d';
import { UserAuthTypeEnum } from '@/constants/common';
import { UserUpdateParams } from '@/types/user';
import { UserType } from '@fastgpt/global/support/user/type.d';
import type { OauthLoginProps, PostLoginProps } from '@fastgpt/global/support/user/api.d';
import type {
FastLoginProps,
OauthLoginProps,
PostLoginProps
} from '@fastgpt/global/support/user/api.d';
export const sendAuthCode = (data: {
username: string;
@@ -16,6 +20,8 @@ export const getTokenLogin = () =>
GET<UserType>('/user/account/tokenLogin', {}, { maxQuantity: 1 });
export const oauthLogin = (params: OauthLoginProps) =>
POST<ResLogin>('/plusApi/support/user/account/login/oauth', params);
export const postFastLogin = (params: FastLoginProps) =>
POST<ResLogin>('/plusApi/support/user/account/login/fastLogin', params);
export const postRegister = ({
username,