This commit is contained in:
archer 2023-08-04 10:06:34 +08:00
parent ffd4e194bf
commit eb28bfb27b
No known key found for this signature in database
GPG Key ID: 569A5660D2379E28
10 changed files with 663 additions and 95 deletions

View File

@ -7,15 +7,16 @@ WORKDIR /app
# Install dependencies based on the preferred package manager # Install dependencies based on the preferred package manager
COPY package.json ./ COPY package.json ./
COPY pnpm-lock.yaml* ./ COPY pnpm-lock.yaml* ./
RUN pnpm config set registry https://registry.npmmirror.com/
RUN \ RUN \
[ -f pnpm-lock.yaml ] && pnpm install || \ [ -f pnpm-lock.yaml ] && pnpm fetch || \
(echo "Lockfile not found." && exit 1) (echo "Lockfile not found." && exit 1)
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM node:current-alpine AS builder FROM node:current-alpine AS builder
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY pnpm-lock.yaml* ./
COPY package.json ./
COPY . . COPY . .
# Next.js collects completely anonymous telemetry data about general usage. # 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. # Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1 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 # Production image, copy all the files and run next
FROM node:current-alpine AS runner FROM node:current-alpine AS runner

File diff suppressed because it is too large Load Diff

View File

@ -25,42 +25,60 @@ const chatModelInput = ({
{ {
key: 'model', key: 'model',
value: model, value: model,
type: 'custom',
label: '对话模型',
connected: true connected: true
}, },
{ {
key: 'temperature', key: 'temperature',
value: temperature, value: temperature,
label: '温度',
type: 'slider',
connected: true connected: true
}, },
{ {
key: 'maxToken', key: 'maxToken',
value: maxToken, value: maxToken,
type: 'custom',
label: '回复上限',
connected: true connected: true
}, },
{ {
key: 'systemPrompt', key: 'systemPrompt',
value: systemPrompt, value: systemPrompt,
type: 'textarea',
label: '系统提示词',
connected: true connected: true
}, },
{ {
key: 'limitPrompt', key: 'limitPrompt',
label: '限定词',
type: 'textarea',
value: limitPrompt, value: limitPrompt,
connected: true connected: true
}, },
{ {
key: 'switch', key: 'switch',
type: 'target',
label: '触发器',
connected: kbList.length > 0 connected: kbList.length > 0
}, },
{ {
key: 'quoteQA', key: 'quoteQA',
type: 'target',
label: '引用内容',
connected: kbList.length > 0 connected: kbList.length > 0
}, },
{ {
key: 'history', key: 'history',
type: 'target',
label: '聊天记录',
connected: true connected: true
}, },
{ {
key: 'userChatInput', key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true connected: true
} }
]; ];

View File

@ -22,7 +22,7 @@ const NodeExtract = ({
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>(); const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
return ( return (
<NodeCard minW={'380px'} moduleId={moduleId} {...props}> <NodeCard minW={'400px'} moduleId={moduleId} {...props}>
<Divider text="Input" /> <Divider text="Input" />
<Container> <Container>
<RenderInput <RenderInput
@ -64,11 +64,14 @@ const NodeExtract = ({
</Thead> </Thead>
<Tbody> <Tbody>
{extractKeys.map((item, index) => ( {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>{item.key}</Td>
<Td whiteSpace={'pre-wrap'} wordBreak={'break-all'}> <Td>{item.desc}</Td>
{item.desc}
</Td>
<Td>{item.required ? '✔' : ''}</Td> <Td>{item.required ? '✔' : ''}</Td>
<Td whiteSpace={'nowrap'}> <Td whiteSpace={'nowrap'}>
<MyIcon <MyIcon
@ -139,24 +142,6 @@ const NodeExtract = ({
const newInputs = exists const newInputs = exists
? extracts.map((item) => (item.key === editExtractFiled.key ? data : item)) ? extracts.map((item) => (item.key === editExtractFiled.key ? data : item))
: extracts.concat(data); : 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({ onChangeNode({
moduleId, moduleId,
@ -167,15 +152,63 @@ const NodeExtract = ({
value: newInputs value: newInputs
} }
}); });
onChangeNode({
moduleId,
type: 'outputs',
key: '',
value: newOutputs
});
if (editExtractFiled.key && editExtractFiled.key !== data.key) { if (!exists) {
onDelEdge({ moduleId, sourceHandle: editExtractFiled.key }); 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); setEditExtractField(undefined);
@ -186,4 +219,4 @@ const NodeExtract = ({
); );
}; };
export default NodeExtract; export default React.memo(NodeExtract);

View File

@ -34,7 +34,6 @@ const ExtractFieldModal = ({
const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({ const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({
defaultValues: defaultField defaultValues: defaultField
}); });
const isEdit = useMemo(() => !!defaultField.key, [defaultField]);
return ( return (
<MyModal isOpen={true} onClose={onClose}> <MyModal isOpen={true} onClose={onClose}>
@ -56,17 +55,11 @@ const ExtractFieldModal = ({
</Flex> </Flex>
<Flex mt={5} alignItems={'center'}> <Flex mt={5} alignItems={'center'}>
<Box flex={'0 0 70px'}> key</Box> <Box flex={'0 0 70px'}> key</Box>
<MyTooltip label={isEdit ? '不支持修改 key' : ''} shouldWrapChildren={false}> <Input
<Input placeholder="name/age/sql"
isDisabled={isEdit} {...register('key', { required: '字段 key 不能为空' })}
placeholder="name/age/sql" />
{...register('key', { required: '字段 key 不能为空' })}
/>
</MyTooltip>
</Flex> </Flex>
<Box mt={1} pl={'70px'} color={'myGray.600'} fontSize={'sm'}>
注意: key
</Box>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@ -114,11 +114,13 @@ export const Label = ({
key: data.key, key: data.key,
value: data value: data
}); });
onChangeNode({ setTimeout(() => {
moduleId, onChangeNode({
type: 'delInput', moduleId,
key: editField.key, type: 'delInput',
value: '' key: editField.key,
value: ''
});
}); });
} }
setEditField(undefined); setEditField(undefined);

View File

@ -77,12 +77,31 @@ const Label = ({
defaultField={editField} defaultField={editField}
onClose={() => setEditField(undefined)} onClose={() => setEditField(undefined)}
onSubmit={(data) => { onSubmit={(data) => {
onChangeNode({ if (editField.key === data.key) {
moduleId, onChangeNode({
type: 'outputs', moduleId,
key: '', type: 'outputs',
value: outputs.map((output) => (output.key === outputKey ? data : output)) 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); setEditField(undefined);
}} }}

View File

@ -42,4 +42,4 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
); );
}; };
export default SourceHandle; export default React.memo(SourceHandle);

View File

@ -3,10 +3,12 @@ import { Flex, Box, IconButton } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/store/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
const SliderApps = ({ appId }: { appId: string }) => { const SliderApps = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const { myApps, loadMyApps } = useUserStore(); const { myApps, loadMyApps } = useUserStore();
@ -33,7 +35,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
borderRadius={'50%'} borderRadius={'50%'}
aria-label={''} aria-label={''}
/> />
退 {t('chat.Exit Chat')}
</Flex> </Flex>
<Box mt={5}> <Box mt={5}>
{myApps.map((item) => ( {myApps.map((item) => (

View File

@ -1,6 +1,11 @@
import type { AppModuleItemType, VariableItemType } from '@/types/app'; import type { AppModuleItemType, VariableItemType } from '@/types/app';
import { chatModelList, vectorModelList } from '@/store/static'; 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 { SystemInputEnum } from '@/constants/app';
import { TaskResponseKeyEnum } from '@/constants/chat'; import { TaskResponseKeyEnum } from '@/constants/chat';
import type { SelectedKbType } from '@/types/plugin'; import type { SelectedKbType } from '@/types/plugin';
@ -153,42 +158,60 @@ const chatModelInput = (formData: EditFormType): FlowInputItemType[] => [
{ {
key: 'model', key: 'model',
value: formData.chatModel.model, value: formData.chatModel.model,
type: 'custom',
label: '对话模型',
connected: true connected: true
}, },
{ {
key: 'temperature', key: 'temperature',
value: formData.chatModel.temperature, value: formData.chatModel.temperature,
type: 'slider',
label: '温度',
connected: true connected: true
}, },
{ {
key: 'maxToken', key: 'maxToken',
value: formData.chatModel.maxToken, value: formData.chatModel.maxToken,
type: 'custom',
label: '回复上限',
connected: true connected: true
}, },
{ {
key: 'systemPrompt', key: 'systemPrompt',
value: formData.chatModel.systemPrompt, value: formData.chatModel.systemPrompt,
type: 'textarea',
label: '系统提示词',
connected: true connected: true
}, },
{ {
key: 'limitPrompt', key: 'limitPrompt',
type: 'textarea',
value: formData.chatModel.limitPrompt, value: formData.chatModel.limitPrompt,
label: '限定词',
connected: true connected: true
}, },
{ {
key: 'switch', key: 'switch',
type: 'target',
label: '触发器',
connected: formData.kb.list.length > 0 connected: formData.kb.list.length > 0
}, },
{ {
key: 'quoteQA', key: 'quoteQA',
type: 'target',
label: '引用内容',
connected: formData.kb.list.length > 0 connected: formData.kb.list.length > 0
}, },
{ {
key: 'history', key: 'history',
type: 'target',
label: '聊天记录',
connected: true connected: true
}, },
{ {
key: 'userChatInput', key: 'userChatInput',
type: 'target',
label: '用户问题',
connected: true connected: true
} }
]; ];
@ -200,6 +223,8 @@ const welcomeTemplate = (formData: EditFormType): AppModuleItemType[] =>
inputs: [ inputs: [
{ {
key: 'welcomeText', key: 'welcomeText',
type: 'input',
label: '开场白',
value: formData.guide.welcome.text, value: formData.guide.welcome.text,
connected: true connected: true
} }
@ -222,6 +247,8 @@ const variableTemplate = (formData: EditFormType): AppModuleItemType[] =>
{ {
key: 'variables', key: 'variables',
value: formData.variables, value: formData.variables,
type: 'systemInput',
label: '变量输入',
connected: true connected: true
} }
], ],
@ -240,7 +267,9 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [
inputs: [ inputs: [
{ {
key: 'userChatInput', key: 'userChatInput',
connected: true connected: true,
label: '用户问题',
type: 'target'
} }
], ],
outputs: [ outputs: [
@ -266,10 +295,14 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [
{ {
key: 'maxContext', key: 'maxContext',
value: 6, value: 6,
connected: true connected: true,
type: 'numberInput',
label: '最长记录数'
}, },
{ {
key: 'history', key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true connected: true
} }
], ],
@ -312,6 +345,8 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
inputs: [ inputs: [
{ {
key: 'userChatInput', key: 'userChatInput',
label: '用户问题',
type: 'target',
connected: true connected: true
} }
], ],
@ -342,10 +377,14 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
{ {
key: 'maxContext', key: 'maxContext',
value: 6, value: 6,
connected: true connected: true,
type: 'numberInput',
label: '最长记录数'
}, },
{ {
key: 'history', key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true connected: true
} }
], ],
@ -372,24 +411,34 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
{ {
key: 'kbList', key: 'kbList',
value: formData.kb.list, value: formData.kb.list,
type: FlowInputItemTypeEnum.custom,
label: '关联的知识库',
connected: true connected: true
}, },
{ {
key: 'similarity', key: 'similarity',
value: formData.kb.searchSimilarity, value: formData.kb.searchSimilarity,
type: FlowInputItemTypeEnum.slider,
label: '相似度',
connected: true connected: true
}, },
{ {
key: 'limit', key: 'limit',
value: formData.kb.searchLimit, value: formData.kb.searchLimit,
type: FlowInputItemTypeEnum.slider,
label: '单次搜索上限',
connected: true connected: true
}, },
{ {
key: 'switch', key: 'switch',
type: FlowInputItemTypeEnum.target,
label: '触发器',
connected: false connected: false
}, },
{ {
key: 'userChatInput', key: 'userChatInput',
type: FlowInputItemTypeEnum.target,
label: '用户问题',
connected: true connected: true
} }
], ],
@ -442,11 +491,16 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
inputs: [ inputs: [
{ {
key: 'switch', key: 'switch',
type: FlowInputItemTypeEnum.target,
label: '触发器',
connected: true connected: true
}, },
{ {
key: SpecialInputKeyEnum.answerText, key: SpecialInputKeyEnum.answerText,
value: formData.kb.searchEmptyText, value: formData.kb.searchEmptyText,
type: FlowInputItemTypeEnum.textarea,
valueType: FlowValueTypeEnum.string,
label: '回复的内容',
connected: true connected: true
} }
], ],