mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-24 13:35:12 +00:00
perf: ts
This commit is contained in:
@@ -7,15 +7,16 @@ WORKDIR /app
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json ./
|
||||
COPY pnpm-lock.yaml* ./
|
||||
RUN pnpm config set registry https://registry.npmmirror.com/
|
||||
RUN \
|
||||
[ -f pnpm-lock.yaml ] && pnpm install || \
|
||||
[ -f pnpm-lock.yaml ] && pnpm fetch || \
|
||||
(echo "Lockfile not found." && exit 1)
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM node:current-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY pnpm-lock.yaml* ./
|
||||
COPY package.json ./
|
||||
COPY . .
|
||||
|
||||
# Next.js collects completely anonymous telemetry data about general usage.
|
||||
@@ -23,7 +24,10 @@ COPY . .
|
||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN npm install -g pnpm && pnpm run build
|
||||
RUN npm install -g pnpm
|
||||
RUN \
|
||||
[ -f pnpm-lock.yaml ] && (pnpm --offline install && pnpm run build) || \
|
||||
(echo "Lockfile not found." && exit 1)
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM node:current-alpine AS runner
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -25,42 +25,60 @@ const chatModelInput = ({
|
||||
{
|
||||
key: 'model',
|
||||
value: model,
|
||||
type: 'custom',
|
||||
label: '对话模型',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'temperature',
|
||||
value: temperature,
|
||||
label: '温度',
|
||||
type: 'slider',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'maxToken',
|
||||
value: maxToken,
|
||||
type: 'custom',
|
||||
label: '回复上限',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'systemPrompt',
|
||||
value: systemPrompt,
|
||||
type: 'textarea',
|
||||
label: '系统提示词',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'limitPrompt',
|
||||
label: '限定词',
|
||||
type: 'textarea',
|
||||
value: limitPrompt,
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'switch',
|
||||
type: 'target',
|
||||
label: '触发器',
|
||||
connected: kbList.length > 0
|
||||
},
|
||||
{
|
||||
key: 'quoteQA',
|
||||
type: 'target',
|
||||
label: '引用内容',
|
||||
connected: kbList.length > 0
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
type: 'target',
|
||||
label: '聊天记录',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'userChatInput',
|
||||
type: 'target',
|
||||
label: '用户问题',
|
||||
connected: true
|
||||
}
|
||||
];
|
||||
|
@@ -22,7 +22,7 @@ const NodeExtract = ({
|
||||
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
|
||||
|
||||
return (
|
||||
<NodeCard minW={'380px'} moduleId={moduleId} {...props}>
|
||||
<NodeCard minW={'400px'} moduleId={moduleId} {...props}>
|
||||
<Divider text="Input" />
|
||||
<Container>
|
||||
<RenderInput
|
||||
@@ -64,11 +64,14 @@ const NodeExtract = ({
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{extractKeys.map((item, index) => (
|
||||
<Tr key={index} position={'relative'}>
|
||||
<Tr
|
||||
key={index}
|
||||
position={'relative'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
wordBreak={'break-all'}
|
||||
>
|
||||
<Td>{item.key}</Td>
|
||||
<Td whiteSpace={'pre-wrap'} wordBreak={'break-all'}>
|
||||
{item.desc}
|
||||
</Td>
|
||||
<Td>{item.desc}</Td>
|
||||
<Td>{item.required ? '✔' : ''}</Td>
|
||||
<Td whiteSpace={'nowrap'}>
|
||||
<MyIcon
|
||||
@@ -139,24 +142,6 @@ const NodeExtract = ({
|
||||
const newInputs = exists
|
||||
? extracts.map((item) => (item.key === editExtractFiled.key ? data : item))
|
||||
: extracts.concat(data);
|
||||
const newOutputs = exists
|
||||
? outputs.map((output) =>
|
||||
output.key === editExtractFiled.key
|
||||
? {
|
||||
...output,
|
||||
key: data.key,
|
||||
label: `提取结果-${data.desc}`
|
||||
}
|
||||
: output
|
||||
)
|
||||
: outputs.concat({
|
||||
key: data.key,
|
||||
label: `提取结果-${data.desc}`,
|
||||
description: '无法提取时不会返回',
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
targets: []
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
@@ -167,15 +152,63 @@ const NodeExtract = ({
|
||||
value: newInputs
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: newOutputs
|
||||
});
|
||||
|
||||
if (editExtractFiled.key && editExtractFiled.key !== data.key) {
|
||||
onDelEdge({ moduleId, sourceHandle: editExtractFiled.key });
|
||||
if (!exists) {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: outputs.concat({
|
||||
key: data.key,
|
||||
label: `提取结果-${data.desc}`,
|
||||
description: '无法提取时不会返回',
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
targets: []
|
||||
})
|
||||
});
|
||||
} else {
|
||||
if (editExtractFiled.key === data.key) {
|
||||
// update
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: outputs.map((output) =>
|
||||
output.key === data.key
|
||||
? {
|
||||
...output,
|
||||
label: `提取结果-${data.desc}`
|
||||
}
|
||||
: output
|
||||
)
|
||||
});
|
||||
} else {
|
||||
// del and push
|
||||
const newOutputs = outputs.filter((output) => output.key !== editExtractFiled.key);
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: newOutputs
|
||||
});
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: newOutputs.concat({
|
||||
key: data.key,
|
||||
label: `提取结果-${data.desc}`,
|
||||
description: '无法提取时不会返回',
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
targets: []
|
||||
})
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
|
||||
setEditExtractField(undefined);
|
||||
@@ -186,4 +219,4 @@ const NodeExtract = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeExtract;
|
||||
export default React.memo(NodeExtract);
|
||||
|
@@ -34,7 +34,6 @@ const ExtractFieldModal = ({
|
||||
const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({
|
||||
defaultValues: defaultField
|
||||
});
|
||||
const isEdit = useMemo(() => !!defaultField.key, [defaultField]);
|
||||
|
||||
return (
|
||||
<MyModal isOpen={true} onClose={onClose}>
|
||||
@@ -56,17 +55,11 @@ const ExtractFieldModal = ({
|
||||
</Flex>
|
||||
<Flex mt={5} alignItems={'center'}>
|
||||
<Box flex={'0 0 70px'}>字段 key</Box>
|
||||
<MyTooltip label={isEdit ? '不支持修改 key' : ''} shouldWrapChildren={false}>
|
||||
<Input
|
||||
isDisabled={isEdit}
|
||||
placeholder="name/age/sql"
|
||||
{...register('key', { required: '字段 key 不能为空' })}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<Input
|
||||
placeholder="name/age/sql"
|
||||
{...register('key', { required: '字段 key 不能为空' })}
|
||||
/>
|
||||
</Flex>
|
||||
<Box mt={1} pl={'70px'} color={'myGray.600'} fontSize={'sm'}>
|
||||
注意: key 字段创建后无法修改
|
||||
</Box>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
|
@@ -114,11 +114,13 @@ export const Label = ({
|
||||
key: data.key,
|
||||
value: data
|
||||
});
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'delInput',
|
||||
key: editField.key,
|
||||
value: ''
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'delInput',
|
||||
key: editField.key,
|
||||
value: ''
|
||||
});
|
||||
});
|
||||
}
|
||||
setEditField(undefined);
|
||||
|
@@ -77,12 +77,31 @@ const Label = ({
|
||||
defaultField={editField}
|
||||
onClose={() => setEditField(undefined)}
|
||||
onSubmit={(data) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: outputs.map((output) => (output.key === outputKey ? data : output))
|
||||
});
|
||||
if (editField.key === data.key) {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: outputs.map((output) => (output.key === outputKey ? data : output))
|
||||
});
|
||||
} else {
|
||||
const storeOutputs = outputs.filter((output) => output.key !== editField.key);
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: storeOutputs
|
||||
});
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'outputs',
|
||||
key: '',
|
||||
value: storeOutputs.concat(data)
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
|
||||
setEditField(undefined);
|
||||
}}
|
||||
|
@@ -42,4 +42,4 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default SourceHandle;
|
||||
export default React.memo(SourceHandle);
|
||||
|
@@ -3,10 +3,12 @@ import { Flex, Box, IconButton } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import Avatar from '@/components/Avatar';
|
||||
|
||||
const SliderApps = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const { myApps, loadMyApps } = useUserStore();
|
||||
|
||||
@@ -33,7 +35,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
|
||||
borderRadius={'50%'}
|
||||
aria-label={''}
|
||||
/>
|
||||
退出聊天
|
||||
{t('chat.Exit Chat')}
|
||||
</Flex>
|
||||
<Box mt={5}>
|
||||
{myApps.map((item) => (
|
||||
|
@@ -1,6 +1,11 @@
|
||||
import type { AppModuleItemType, VariableItemType } from '@/types/app';
|
||||
import { chatModelList, vectorModelList } from '@/store/static';
|
||||
import { FlowModuleTypeEnum, SpecialInputKeyEnum } from '@/constants/flow';
|
||||
import {
|
||||
FlowInputItemTypeEnum,
|
||||
FlowModuleTypeEnum,
|
||||
FlowValueTypeEnum,
|
||||
SpecialInputKeyEnum
|
||||
} from '@/constants/flow';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import type { SelectedKbType } from '@/types/plugin';
|
||||
@@ -153,42 +158,60 @@ const chatModelInput = (formData: EditFormType): FlowInputItemType[] => [
|
||||
{
|
||||
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: 'limitPrompt',
|
||||
type: 'textarea',
|
||||
value: formData.chatModel.limitPrompt,
|
||||
label: '限定词',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'switch',
|
||||
type: 'target',
|
||||
label: '触发器',
|
||||
connected: formData.kb.list.length > 0
|
||||
},
|
||||
{
|
||||
key: 'quoteQA',
|
||||
type: 'target',
|
||||
label: '引用内容',
|
||||
connected: formData.kb.list.length > 0
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
type: 'target',
|
||||
label: '聊天记录',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'userChatInput',
|
||||
type: 'target',
|
||||
label: '用户问题',
|
||||
connected: true
|
||||
}
|
||||
];
|
||||
@@ -200,6 +223,8 @@ const welcomeTemplate = (formData: EditFormType): AppModuleItemType[] =>
|
||||
inputs: [
|
||||
{
|
||||
key: 'welcomeText',
|
||||
type: 'input',
|
||||
label: '开场白',
|
||||
value: formData.guide.welcome.text,
|
||||
connected: true
|
||||
}
|
||||
@@ -222,6 +247,8 @@ const variableTemplate = (formData: EditFormType): AppModuleItemType[] =>
|
||||
{
|
||||
key: 'variables',
|
||||
value: formData.variables,
|
||||
type: 'systemInput',
|
||||
label: '变量输入',
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
@@ -240,7 +267,9 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
||||
inputs: [
|
||||
{
|
||||
key: 'userChatInput',
|
||||
connected: true
|
||||
connected: true,
|
||||
label: '用户问题',
|
||||
type: 'target'
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
@@ -266,10 +295,14 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
||||
{
|
||||
key: 'maxContext',
|
||||
value: 6,
|
||||
connected: true
|
||||
connected: true,
|
||||
type: 'numberInput',
|
||||
label: '最长记录数'
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
type: 'hidden',
|
||||
label: '聊天记录',
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
@@ -312,6 +345,8 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
||||
inputs: [
|
||||
{
|
||||
key: 'userChatInput',
|
||||
label: '用户问题',
|
||||
type: 'target',
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
@@ -342,10 +377,14 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
||||
{
|
||||
key: 'maxContext',
|
||||
value: 6,
|
||||
connected: true
|
||||
connected: true,
|
||||
type: 'numberInput',
|
||||
label: '最长记录数'
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
type: 'hidden',
|
||||
label: '聊天记录',
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
@@ -372,24 +411,34 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
||||
{
|
||||
key: 'kbList',
|
||||
value: formData.kb.list,
|
||||
type: FlowInputItemTypeEnum.custom,
|
||||
label: '关联的知识库',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'similarity',
|
||||
value: formData.kb.searchSimilarity,
|
||||
type: FlowInputItemTypeEnum.slider,
|
||||
label: '相似度',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'limit',
|
||||
value: formData.kb.searchLimit,
|
||||
type: FlowInputItemTypeEnum.slider,
|
||||
label: '单次搜索上限',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'switch',
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '触发器',
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'userChatInput',
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '用户问题',
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
@@ -442,11 +491,16 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
||||
inputs: [
|
||||
{
|
||||
key: 'switch',
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '触发器',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: SpecialInputKeyEnum.answerText,
|
||||
value: formData.kb.searchEmptyText,
|
||||
type: FlowInputItemTypeEnum.textarea,
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
label: '回复的内容',
|
||||
connected: true
|
||||
}
|
||||
],
|
||||
|
Reference in New Issue
Block a user