extract modules

This commit is contained in:
archer
2023-07-31 18:17:27 +08:00
parent 2f28f57d78
commit 58153306c5
17 changed files with 377 additions and 78 deletions

View File

@@ -18,6 +18,13 @@
"New Chat": "New Chat", "New Chat": "New Chat",
"You need to a chat app": "You need to a chat app" "You need to a chat app": "You need to a chat app"
}, },
"common": {
"Add": "Add",
"Filed is repeat": "Filed is repeated",
"Filed is repeated": "",
"Input": "Input",
"Output": "Output"
},
"home": { "home": {
"Quickly build AI question and answer library": "Quickly build AI question and answer library", "Quickly build AI question and answer library": "Quickly build AI question and answer library",
"Start Now": "Start Now", "Start Now": "Start Now",

View File

@@ -18,6 +18,13 @@
"New Chat": "新对话", "New Chat": "新对话",
"You need to a chat app": "你需要创建一个应用" "You need to a chat app": "你需要创建一个应用"
}, },
"common": {
"Add": "添加",
"Filed is repeat": "",
"Filed is repeated": "字段重复了",
"Input": "输入",
"Output": "输出"
},
"home": { "home": {
"Quickly build AI question and answer library": "快速搭建 AI 问答系统", "Quickly build AI question and answer library": "快速搭建 AI 问答系统",
"Start Now": "立即开始", "Start Now": "立即开始",

View File

@@ -54,7 +54,8 @@ export const ChatSourceMap = {
export enum ChatModuleEnum { export enum ChatModuleEnum {
'AIChat' = 'AI Chat', 'AIChat' = 'AI Chat',
'KBSearch' = 'KB Search', 'KBSearch' = 'KB Search',
'CQ' = 'Classify Question' 'CQ' = 'Classify Question',
'Extract' = 'Content Extract'
} }
export enum OutLinkTypeEnum { export enum OutLinkTypeEnum {

View File

@@ -15,6 +15,7 @@ import {
Input_Template_TFSwitch, Input_Template_TFSwitch,
Input_Template_UserChatInput Input_Template_UserChatInput
} from './inputTemplate'; } from './inputTemplate';
import { ContextExtractEnum } from './flowField';
export const ChatModelSystemTip = export const ChatModelSystemTip =
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}'; '模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}';
@@ -333,7 +334,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
Input_Template_History, Input_Template_History,
Input_Template_UserChatInput, Input_Template_UserChatInput,
{ {
key: 'agents', key: SpecialInputKeyEnum.agents,
type: FlowInputItemTypeEnum.custom, type: FlowInputItemTypeEnum.custom,
label: '', label: '',
value: [ value: [
@@ -375,59 +376,70 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
}; };
export const ContextExtractModule: FlowModuleTemplateType = { export const ContextExtractModule: FlowModuleTemplateType = {
logo: '/imgs/module/extract.png', logo: '/imgs/module/extract.png',
name: '内容提取', name: '文本内容提取',
intro: '从文本中提取出指定格式的数据', intro: '从文本中提取出指定格式的数据',
description: '可从文本中提取指定的数据例如sql语句、搜索关键词、代码等', description: '可从文本中提取指定的数据例如sql语句、搜索关键词、代码等',
flowType: FlowModuleTypeEnum.contentExtract, flowType: FlowModuleTypeEnum.contentExtract,
inputs: [ inputs: [
Input_Template_TFSwitch,
{ {
key: 'systemPrompt', key: ContextExtractEnum.description,
type: FlowInputItemTypeEnum.textarea, type: FlowInputItemTypeEnum.textarea,
valueType: FlowValueTypeEnum.string, valueType: FlowValueTypeEnum.string,
label: '提取内容描述', label: '提取要求描述',
description: '写一段提取要求,告诉 AI 需要提取哪些内容', description: '写一段提取要求,告诉 AI 需要提取哪些内容',
placeholder: '例如: \n1. 根据用户的\n2. Sealos 是一个集群操作系统', placeholder:
'例如: \n1. 你是一个实验室预约助手。根据用户问题,提取出姓名、实验室号和预约时间',
value: '' value: ''
}, },
Input_Template_History, Input_Template_History,
Input_Template_UserChatInput,
{ {
key: 'agents', key: ContextExtractEnum.content,
type: FlowInputItemTypeEnum.target,
label: '需要提取的文本',
required: true,
valueType: FlowValueTypeEnum.string
},
{
key: ContextExtractEnum.extractKeys,
type: FlowInputItemTypeEnum.custom, type: FlowInputItemTypeEnum.custom,
label: '', label: '目标字段',
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
value: [ value: [
{ {
value: '打招呼', key: 'a',
key: 'fasw' desc: '描述',
required: true
}, },
{ {
value: '关于 xxx 的问题', key: 'n',
key: 'fqsw' desc: '描述',
}, required: true
{
value: '其他问题',
key: 'fesw'
} }
] ]
} }
], ],
outputs: [ outputs: [
{ {
key: 'fasw', key: ContextExtractEnum.success,
label: '', label: '字段完全提取',
type: FlowOutputItemTypeEnum.hidden, valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: [] targets: []
}, },
{ {
key: 'fqsw', key: ContextExtractEnum.failed,
label: '', label: '提取字段缺失',
type: FlowOutputItemTypeEnum.hidden, valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: [] targets: []
}, },
{ {
key: 'fesw', key: ContextExtractEnum.fields,
label: '', label: '提取结果',
type: FlowOutputItemTypeEnum.hidden, description: '一个 JSON 对象,例如 {"name:":"YY","Time":"2023/7/2 18:00"}',
valueType: FlowValueTypeEnum.other,
type: FlowOutputItemTypeEnum.source,
targets: [] targets: []
} }
] ]
@@ -461,7 +473,7 @@ export const ModuleTemplates = [
}, },
{ {
label: 'Agent', label: 'Agent',
list: [ClassifyQuestionModule] list: [ClassifyQuestionModule, ContextExtractModule]
} }
]; ];
export const ModuleTemplatesFlat = ModuleTemplates.map((templates) => templates.list)?.flat(); export const ModuleTemplatesFlat = ModuleTemplates.map((templates) => templates.list)?.flat();
@@ -1070,7 +1082,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] =
connected: true connected: true
}, },
{ {
key: 'agents', key: SpecialInputKeyEnum.agents,
value: [ value: [
{ {
value: '打招呼、问候等问题', value: '打招呼、问候等问题',

View File

@@ -0,0 +1,8 @@
export enum ContextExtractEnum {
extractKeys = 'extractKeys',
content = 'content',
description = 'description',
success = 'success',
failed = 'failed',
fields = 'fields'
}

View File

@@ -35,7 +35,8 @@ export enum FlowModuleTypeEnum {
} }
export enum SpecialInputKeyEnum { export enum SpecialInputKeyEnum {
'answerText' = 'text' 'answerText' = 'text',
'agents' = 'agents' // cq agent key
} }
export enum FlowValueTypeEnum { export enum FlowValueTypeEnum {

View File

@@ -25,6 +25,7 @@ import { pushTaskBill } from '@/service/events/pushBill';
import { BillSourceEnum } from '@/constants/user'; import { BillSourceEnum } from '@/constants/user';
import { ChatHistoryItemResType } from '@/types/chat'; import { ChatHistoryItemResType } from '@/types/chat';
import { UserModelSchema } from '@/types/mongoSchema'; import { UserModelSchema } from '@/types/mongoSchema';
import { dispatchContentExtract } from '@/service/moduleDispatch/agent/extract';
export type MessageItemType = ChatCompletionRequestMessage & { _id?: string }; export type MessageItemType = ChatCompletionRequestMessage & { _id?: string };
type FastGptWebChatProps = { type FastGptWebChatProps = {
@@ -337,7 +338,8 @@ export async function dispatchModules({
[FlowModuleTypeEnum.answerNode]: dispatchAnswer, [FlowModuleTypeEnum.answerNode]: dispatchAnswer,
[FlowModuleTypeEnum.chatNode]: dispatchChatCompletion, [FlowModuleTypeEnum.chatNode]: dispatchChatCompletion,
[FlowModuleTypeEnum.kbSearchNode]: dispatchKBSearch, [FlowModuleTypeEnum.kbSearchNode]: dispatchKBSearch,
[FlowModuleTypeEnum.classifyQuestion]: dispatchClassifyQuestion [FlowModuleTypeEnum.classifyQuestion]: dispatchClassifyQuestion,
[FlowModuleTypeEnum.contentExtract]: dispatchContentExtract
}; };
if (callbackMap[module.flowType]) { if (callbackMap[module.flowType]) {
return callbackMap[module.flowType](props); return callbackMap[module.flowType](props);

View File

@@ -10,7 +10,7 @@ import type { ClassifyQuestionAgentItemType } from '@/types/app';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 4); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 4);
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { FlowOutputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow'; import { FlowOutputItemTypeEnum, FlowValueTypeEnum, SpecialInputKeyEnum } from '@/constants/flow';
import SourceHandle from '../render/SourceHandle'; import SourceHandle from '../render/SourceHandle';
const NodeCQNode = ({ const NodeCQNode = ({
@@ -25,7 +25,7 @@ const NodeCQNode = ({
onChangeNode={onChangeNode} onChangeNode={onChangeNode}
flowInputList={inputs} flowInputList={inputs}
CustomComponent={{ CustomComponent={{
agents: ({ [SpecialInputKeyEnum.agents]: ({
key: agentKey, key: agentKey,
value: agents = [] value: agents = []
}: { }: {

View File

@@ -0,0 +1,146 @@
import React, { useState } from 'react';
import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react';
import { NodeProps } from 'reactflow';
import { FlowModuleItemType } from '@/types/flow';
import { useTranslation } from 'next-i18next';
import NodeCard from '../modules/NodeCard';
import Container from '../modules/Container';
import { AddIcon } from '@chakra-ui/icons';
import RenderInput from '../render/RenderInput';
import Divider from '../modules/Divider';
import { ContextExtractAgentItemType } from '@/types/app';
import RenderOutput from '../render/RenderOutput';
import MyIcon from '@/components/Icon';
import ExtractFieldModal from '../modules/ExtractFieldModal';
import { ContextExtractEnum } from '@/constants/flow/flowField';
const NodeExtract = ({
data: { inputs, outputs, moduleId, onChangeNode, ...props }
}: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
return (
<NodeCard minW={'380px'} moduleId={moduleId} {...props}>
<Divider text="Input" />
<Container>
<RenderInput
moduleId={moduleId}
onChangeNode={onChangeNode}
flowInputList={inputs}
CustomComponent={{
[ContextExtractEnum.extractKeys]: ({
key,
value: extractKeys = []
}: {
key: string;
value?: ContextExtractAgentItemType[];
}) => (
<Box>
<TableContainer>
<Table>
<Thead>
<Tr>
<Th> key</Th>
<Th></Th>
<Th></Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{extractKeys.map((item, index) => (
<Tr key={index}>
<Td>{item.key}</Td>
<Td whiteSpace={'pre-line'} wordBreak={'break-all'}>
{item.desc}{' '}
</Td>
<Td>{item.required ? '✔' : ''}</Td>
<Td whiteSpace={'nowrap'}>
<MyIcon
mr={3}
name={'settingLight'}
w={'16px'}
cursor={'pointer'}
onClick={() => {
setEditExtractField(item);
}}
/>
<MyIcon
name={'delete'}
w={'16px'}
cursor={'pointer'}
onClick={() => {
onChangeNode({
moduleId,
type: 'inputs',
key: ContextExtractEnum.extractKeys,
value: extractKeys.filter((extract) => item.key !== extract.key)
});
}}
/>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
<Box mt={2} textAlign={'right'}>
<Button
variant={'base'}
leftIcon={<AddIcon fontSize={'10px'} />}
onClick={() =>
setEditExtractField({
desc: '',
key: '',
required: true
})
}
>
</Button>
</Box>
</Box>
)
}}
/>
</Container>
<Divider text="Output" />
<Container>
<RenderOutput flowOutputList={outputs} />
</Container>
{!!editExtractFiled && (
<ExtractFieldModal
defaultField={editExtractFiled}
onClose={() => setEditExtractField(undefined)}
onSubmit={(data) => {
const extracts: ContextExtractAgentItemType[] =
inputs.find((item) => item.key === ContextExtractEnum.extractKeys)?.value || [];
const exists = extracts.find((item) => item.key === editExtractFiled.key);
if (exists) {
onChangeNode({
moduleId,
type: 'inputs',
key: ContextExtractEnum.extractKeys,
value: extracts.map((item) => (item.key === editExtractFiled.key ? data : item))
});
} else {
onChangeNode({
moduleId,
type: 'inputs',
key: ContextExtractEnum.extractKeys,
value: extracts.concat(data)
});
}
setEditExtractField(undefined);
}}
/>
)}
</NodeCard>
);
};
export default NodeExtract;

View File

@@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import { Box, useTheme } from '@chakra-ui/react'; import { Box, useTheme } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
const Divider = ({ text }: { text: 'Body' | 'Input' | 'Output' | string }) => { const Divider = ({ text }: { text: 'Input' | 'Output' | string }) => {
const theme = useTheme(); const theme = useTheme();
const { t } = useTranslation();
return ( return (
<Box <Box
textAlign={'center'} textAlign={'center'}
@@ -12,7 +14,7 @@ const Divider = ({ text }: { text: 'Body' | 'Input' | 'Output' | string }) => {
borderBottom={theme.borders.base} borderBottom={theme.borders.base}
fontSize={'lg'} fontSize={'lg'}
> >
{text} {t(`common.${text}`)}
</Box> </Box>
); );
}; };

View File

@@ -0,0 +1,74 @@
import React, { useState } from 'react';
import {
Box,
Button,
ModalHeader,
ModalFooter,
ModalBody,
Flex,
Switch,
Input,
FormControl
} from '@chakra-ui/react';
import type { ContextExtractAgentItemType } from '@/types/app';
import { useForm } from 'react-hook-form';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import MyModal from '@/components/MyModal';
import Avatar from '@/components/Avatar';
const ExtractFieldModal = ({
defaultField = {
desc: '',
key: '',
required: true
},
onClose,
onSubmit
}: {
defaultField?: ContextExtractAgentItemType;
onClose: () => void;
onSubmit: (data: ContextExtractAgentItemType) => void;
}) => {
const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({
defaultValues: defaultField
});
return (
<MyModal isOpen={true} onClose={onClose}>
<ModalHeader display={'flex'} alignItems={'center'}>
<Avatar src={'/imgs/module/extract.png'} mr={2} w={'20px'} objectFit={'cover'} />
</ModalHeader>
<ModalBody>
<Flex alignItems={'center'}>
<Box w={'70px'}></Box>
<Switch {...register('required')} />
</Flex>
<Flex mt={5} alignItems={'center'}>
<Box w={'80px'}></Box>
<Input
placeholder="姓名/年龄/sql语句……"
{...register('desc', { required: '字段描述不能为空' })}
/>
</Flex>
<Flex mt={5} alignItems={'center'}>
<Box w={'80px'}> key</Box>
<Input
placeholder="name/age/sql"
{...register('key', { required: '字段 key 不能为空' })}
/>
</Flex>
</ModalBody>
<ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}>
</Button>
<Button onClick={handleSubmit(onSubmit)}></Button>
</ModalFooter>
</MyModal>
);
};
export default React.memo(ExtractFieldModal);

View File

@@ -29,7 +29,14 @@ const NodeCard = ({
const theme = useTheme(); const theme = useTheme();
return ( return (
<Box minW={minW} bg={'white'} border={theme.borders.md} borderRadius={'md'} boxShadow={'sm'}> <Box
minW={minW}
maxW={'430px'}
bg={'white'}
border={theme.borders.md}
borderRadius={'md'}
boxShadow={'sm'}
>
<Flex className="custom-drag-handle" px={4} py={3} alignItems={'center'}> <Flex className="custom-drag-handle" px={4} py={3} alignItems={'center'}>
<Avatar src={logo} borderRadius={'md'} objectFit={'contain'} w={'30px'} h={'30px'} /> <Avatar src={logo} borderRadius={'md'} objectFit={'contain'} w={'30px'} h={'30px'} />
<Box ml={3} fontSize={'lg'} color={'myGray.600'}> <Box ml={3} fontSize={'lg'} color={'myGray.600'}>
@@ -39,7 +46,7 @@ const NodeCard = ({
<MyTooltip label={description} forceShow> <MyTooltip label={description} forceShow>
<QuestionOutlineIcon <QuestionOutlineIcon
display={['none', 'inline']} display={['none', 'inline']}
transform={'translateY(-1px)'} transform={'translateY(1px)'}
ml={1} ml={1}
/> />
</MyTooltip> </MyTooltip>

View File

@@ -68,6 +68,9 @@ const NodeVariable = dynamic(() => import('./components/Nodes/NodeVariable'), {
const NodeUserGuide = dynamic(() => import('./components/Nodes/NodeUserGuide'), { const NodeUserGuide = dynamic(() => import('./components/Nodes/NodeUserGuide'), {
ssr: false ssr: false
}); });
const NodeExtract = dynamic(() => import('./components/Nodes/NodeExtract'), {
ssr: false
});
import 'reactflow/dist/style.css'; import 'reactflow/dist/style.css';
import styles from './index.module.scss'; import styles from './index.module.scss';
@@ -83,7 +86,8 @@ const nodeTypes = {
[FlowModuleTypeEnum.kbSearchNode]: NodeKbSearch, [FlowModuleTypeEnum.kbSearchNode]: NodeKbSearch,
[FlowModuleTypeEnum.tfSwitchNode]: NodeTFSwitch, [FlowModuleTypeEnum.tfSwitchNode]: NodeTFSwitch,
[FlowModuleTypeEnum.answerNode]: NodeAnswer, [FlowModuleTypeEnum.answerNode]: NodeAnswer,
[FlowModuleTypeEnum.classifyQuestion]: NodeCQNode [FlowModuleTypeEnum.classifyQuestion]: NodeCQNode,
[FlowModuleTypeEnum.contentExtract]: NodeExtract
// [FlowModuleTypeEnum.empty]: EmptyModule // [FlowModuleTypeEnum.empty]: EmptyModule
}; };
const edgeTypes = { const edgeTypes = {

View File

@@ -8,13 +8,14 @@ import { countModelPrice } from '@/service/events/pushBill';
import { UserModelSchema } from '@/types/mongoSchema'; import { UserModelSchema } from '@/types/mongoSchema';
import { getModel } from '@/service/utils/data'; import { getModel } from '@/service/utils/data';
import { SystemInputEnum } from '@/constants/app'; import { SystemInputEnum } from '@/constants/app';
import { SpecialInputKeyEnum } from '@/constants/flow';
export type CQProps = { export type CQProps = {
systemPrompt?: string; systemPrompt?: string;
history?: ChatItemType[]; history?: ChatItemType[];
[SystemInputEnum.userChatInput]: string; [SystemInputEnum.userChatInput]: string;
userOpenaiAccount: UserModelSchema['openaiAccount']; userOpenaiAccount: UserModelSchema['openaiAccount'];
agents: ClassifyQuestionAgentItemType[]; [SpecialInputKeyEnum.agents]: ClassifyQuestionAgentItemType[];
}; };
export type CQResponse = { export type CQResponse = {
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType; [TaskResponseKeyEnum.responseData]: ChatHistoryItemResType;

View File

@@ -1,50 +1,44 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response';
import { adaptChatItem_openAI } from '@/utils/plugin/openai'; import { adaptChatItem_openAI } from '@/utils/plugin/openai';
import { ChatContextFilter } from '@/service/utils/chat/index'; import { ChatContextFilter } from '@/service/utils/chat/index';
import type { ChatItemType } from '@/types/chat'; import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
import { ChatRoleEnum } from '@/constants/chat'; import { ChatModuleEnum, ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
import { getAIChatApi, axiosConfig } from '@/service/ai/openai'; import { getAIChatApi, axiosConfig } from '@/service/ai/openai';
import type { ClassifyQuestionAgentItemType } from '@/types/app'; import type { ContextExtractAgentItemType } from '@/types/app';
import { SystemInputEnum } from '@/constants/app'; import { ContextExtractEnum } from '@/constants/flow/flowField';
import { countModelPrice } from '@/service/events/pushBill';
import { UserModelSchema } from '@/types/mongoSchema';
import { getModel } from '@/service/utils/data';
export type Props = { export type Props = {
systemPrompt?: string; userOpenaiAccount: UserModelSchema['openaiAccount'];
history?: ChatItemType[]; history?: ChatItemType[];
[SystemInputEnum.userChatInput]: string; [ContextExtractEnum.content]: string;
description: string; [ContextExtractEnum.extractKeys]: ContextExtractAgentItemType[];
agents: ClassifyQuestionAgentItemType[]; [ContextExtractEnum.description]: string;
}; };
export type Response = { export type Response = {
arguments: Record<string, any>; [ContextExtractEnum.success]?: boolean;
deficiency: boolean; [ContextExtractEnum.failed]?: boolean;
[ContextExtractEnum.fields]: Record<string, any>;
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType;
}; };
const agentModel = 'gpt-3.5-turbo'; const agentModel = 'gpt-3.5-turbo';
const agentFunName = 'agent_extract_data'; const agentFunName = 'agent_extract_data';
const maxTokens = 3000; const maxTokens = 3000;
export async function extract({ export async function dispatchContentExtract({
systemPrompt, userOpenaiAccount,
agents, content,
extractKeys,
history = [], history = [],
userChatInput,
description description
}: Props): Promise<Response> { }: Props): Promise<Response> {
const messages: ChatItemType[] = [ const messages: ChatItemType[] = [
...(systemPrompt
? [
{
obj: ChatRoleEnum.System,
value: systemPrompt
}
]
: []),
...history, ...history,
{ {
obj: ChatRoleEnum.Human, obj: ChatRoleEnum.Human,
value: userChatInput value: content
} }
]; ];
const filterMessages = ChatContextFilter({ const filterMessages = ChatContextFilter({
@@ -62,25 +56,25 @@ export async function extract({
description: string; description: string;
} }
> = {}; > = {};
agents.forEach((item) => { extractKeys.forEach((item) => {
properties[item.key] = { properties[item.key] = {
type: 'string', type: 'string',
description: item.value description: item.desc
}; };
}); });
// function body // function body
const agentFunction = { const agentFunction = {
name: agentFunName, name: agentFunName,
description, description: `${description}\n如果内容不存在返回空字符串。当前时间是2023/7/31 18:00`,
parameters: { parameters: {
type: 'object', type: 'object',
properties, properties,
required: agents.map((item) => item.key) required: extractKeys.map((item) => item.key)
} }
}; };
const chatAPI = getAIChatApi(); const chatAPI = getAIChatApi(userOpenaiAccount);
const response = await chatAPI.createChatCompletion( const response = await chatAPI.createChatCompletion(
{ {
@@ -91,21 +85,44 @@ export async function extract({
functions: [agentFunction] functions: [agentFunction]
}, },
{ {
...axiosConfig() ...axiosConfig(userOpenaiAccount)
} }
); );
const arg = JSON.parse(response.data.choices?.[0]?.message?.function_call?.arguments || '{}'); const arg: Record<string, any> = (() => {
let deficiency = false; try {
for (const key in arg) { return JSON.parse(response.data.choices?.[0]?.message?.function_call?.arguments || '{}');
if (arg[key] === '') { } catch (error) {
deficiency = true; return {};
break; }
})();
console.log(adaptMessages, arg);
// auth fields
let success = !extractKeys.find((item) => !arg[item.key]);
// auth empty value
if (success) {
for (const key in arg) {
if (arg[key] === '') {
success = false;
break;
}
} }
} }
const tokens = response.data.usage?.total_tokens || 0;
return { return {
arguments: arg, [ContextExtractEnum.success]: success ? true : undefined,
deficiency [ContextExtractEnum.failed]: success ? undefined : true,
[ContextExtractEnum.fields]: arg,
[TaskResponseKeyEnum.responseData]: {
moduleName: ChatModuleEnum.Extract,
price: userOpenaiAccount?.key ? 0 : countModelPrice({ model: agentModel, tokens }),
model: getModel(agentModel)?.name || agentModel,
tokens,
extractDescription: description,
extractResult: arg
}
}; };
} }

View File

@@ -8,6 +8,7 @@ import {
import type { FlowInputItemType, FlowOutputItemType, FlowOutputTargetItemType } from './flow'; import type { FlowInputItemType, FlowOutputItemType, FlowOutputTargetItemType } from './flow';
import type { AppSchema, kbSchema } from './mongoSchema'; import type { AppSchema, kbSchema } from './mongoSchema';
import { ChatModelType } from '@/constants/model'; import { ChatModelType } from '@/constants/model';
import { FlowValueTypeEnum } from '@/constants/flow';
export type AppListItemType = { export type AppListItemType = {
_id: string; _id: string;
@@ -45,6 +46,11 @@ export type ClassifyQuestionAgentItemType = {
value: string; value: string;
key: string; key: string;
}; };
export type ContextExtractAgentItemType = {
desc: string;
key: string;
required: boolean;
};
export type VariableItemType = { export type VariableItemType = {
id: string; id: string;

View File

@@ -66,4 +66,8 @@ export type ChatHistoryItemResType = {
// cq // cq
cqList?: ClassifyQuestionAgentItemType[]; cqList?: ClassifyQuestionAgentItemType[];
cqResult?: string; cqResult?: string;
// content extract
extractDescription?: string;
extractResult?: Record<string, any>;
}; };