Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
58153306
authored
Jul 31, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
extract modules
parent
2f28f57d
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
377 additions
and
78 deletions
+377
-78
client/public/locales/en/common.json
+7
-0
client/public/locales/zh/common.json
+7
-0
client/src/constants/chat.ts
+2
-1
client/src/constants/flow/ModuleTemplate.ts
+39
-27
client/src/constants/flow/flowField.ts
+8
-0
client/src/constants/flow/index.ts
+2
-1
client/src/pages/api/openapi/v1/chat/completions.ts
+3
-1
client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeCQNode.tsx
+2
-2
client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx
+146
-0
client/src/pages/app/detail/components/AdEdit/components/modules/Divider.tsx
+4
-2
client/src/pages/app/detail/components/AdEdit/components/modules/ExtractFieldModal.tsx
+74
-0
client/src/pages/app/detail/components/AdEdit/components/modules/NodeCard.tsx
+9
-2
client/src/pages/app/detail/components/AdEdit/index.tsx
+5
-1
client/src/service/moduleDispatch/agent/classifyQuestion.ts
+2
-1
client/src/service/moduleDispatch/agent/extract.ts
+57
-40
client/src/types/app.d.ts
+6
-0
client/src/types/chat.d.ts
+4
-0
No files found.
client/public/locales/en/common.json
View file @
58153306
...
...
@@ -18,6 +18,13 @@
"New Chat"
:
"New Chat"
,
"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"
:
{
"Quickly build AI question and answer library"
:
"Quickly build AI question and answer library"
,
"Start Now"
:
"Start Now"
,
...
...
client/public/locales/zh/common.json
View file @
58153306
...
...
@@ -18,6 +18,13 @@
"New Chat"
:
"新对话"
,
"You need to a chat app"
:
"你需要创建一个应用"
},
"common"
:
{
"Add"
:
"添加"
,
"Filed is repeat"
:
""
,
"Filed is repeated"
:
"字段重复了"
,
"Input"
:
"输入"
,
"Output"
:
"输出"
},
"home"
:
{
"Quickly build AI question and answer library"
:
"快速搭建 AI 问答系统"
,
"Start Now"
:
"立即开始"
,
...
...
client/src/constants/chat.ts
View file @
58153306
...
...
@@ -54,7 +54,8 @@ export const ChatSourceMap = {
export
enum
ChatModuleEnum
{
'AIChat'
=
'AI Chat'
,
'KBSearch'
=
'KB Search'
,
'CQ'
=
'Classify Question'
'CQ'
=
'Classify Question'
,
'Extract'
=
'Content Extract'
}
export
enum
OutLinkTypeEnum
{
...
...
client/src/constants/flow/ModuleTemplate.ts
View file @
58153306
...
...
@@ -15,6 +15,7 @@ import {
Input_Template_TFSwitch
,
Input_Template_UserChatInput
}
from
'./inputTemplate'
;
import
{
ContextExtractEnum
}
from
'./flowField'
;
export
const
ChatModelSystemTip
=
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}'
;
...
...
@@ -333,7 +334,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
Input_Template_History,
Input_Template_UserChatInput,
{
key:
'agents'
,
key:
SpecialInputKeyEnum.agents
,
type: FlowInputItemTypeEnum.custom,
label: '',
value: [
...
...
@@ -375,59 +376,70 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
};
export const ContextExtractModule: FlowModuleTemplateType = {
logo: '/imgs/module/extract.png',
name: '内容提取',
name: '
文本
内容提取',
intro: '从文本中提取出指定格式的数据',
description: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
flowType: FlowModuleTypeEnum.contentExtract,
inputs: [
Input_Template_TFSwitch,
{
key:
'systemPrompt'
,
key:
ContextExtractEnum.description
,
type: FlowInputItemTypeEnum.textarea,
valueType: FlowValueTypeEnum.string,
label: '提取
内容
描述',
label: '提取
要求
描述',
description: '写一段提取要求,告诉 AI 需要提取哪些内容',
placeholder: '例如: \n1. 根据用户的\n2. Sealos 是一个集群操作系统',
placeholder:
'例如: \n1. 你是一个实验室预约助手。根据用户问题,提取出姓名、实验室号和预约时间',
value: ''
},
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,
label: '',
label: '目标字段',
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
value: [
{
value: '打招呼',
key: 'fasw'
key: 'a',
desc: '描述',
required: true
},
{
value: '关于 xxx 的问题',
key: 'fqsw'
},
{
value: '其他问题',
key: 'fesw'
key: 'n',
desc: '描述',
required: true
}
]
}
],
outputs: [
{
key: 'fasw',
label: '',
type: FlowOutputItemTypeEnum.hidden,
key: ContextExtractEnum.success,
label: '字段完全提取',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
},
{
key: 'fqsw',
label: '',
type: FlowOutputItemTypeEnum.hidden,
key: ContextExtractEnum.failed,
label: '提取字段缺失',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
},
{
key: 'fesw',
label: '',
type: FlowOutputItemTypeEnum.hidden,
key: ContextExtractEnum.fields,
label: '提取结果',
description: '一个 JSON 对象,例如 {"name:":"YY","Time":"2023/7/2 18:00"}',
valueType: FlowValueTypeEnum.other,
type: FlowOutputItemTypeEnum.source,
targets: []
}
]
...
...
@@ -461,7 +473,7 @@ export const ModuleTemplates = [
},
{
label: 'Agent',
list: [ClassifyQuestionModule]
list: [ClassifyQuestionModule
, ContextExtractModule
]
}
];
export const ModuleTemplatesFlat = ModuleTemplates.map((templates) => templates.list)?.flat();
...
...
@@ -1070,7 +1082,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] =
connected: true
},
{
key:
'agents'
,
key:
SpecialInputKeyEnum.agents
,
value: [
{
value: '打招呼、问候等问题',
...
...
client/src/constants/flow/flowField.ts
0 → 100644
View file @
58153306
export
enum
ContextExtractEnum
{
extractKeys
=
'extractKeys'
,
content
=
'content'
,
description
=
'description'
,
success
=
'success'
,
failed
=
'failed'
,
fields
=
'fields'
}
client/src/constants/flow/index.ts
View file @
58153306
...
...
@@ -35,7 +35,8 @@ export enum FlowModuleTypeEnum {
}
export
enum
SpecialInputKeyEnum
{
'answerText'
=
'text'
'answerText'
=
'text'
,
'agents'
=
'agents'
// cq agent key
}
export
enum
FlowValueTypeEnum
{
...
...
client/src/pages/api/openapi/v1/chat/completions.ts
View file @
58153306
...
...
@@ -25,6 +25,7 @@ import { pushTaskBill } from '@/service/events/pushBill';
import
{
BillSourceEnum
}
from
'@/constants/user'
;
import
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
import
{
UserModelSchema
}
from
'@/types/mongoSchema'
;
import
{
dispatchContentExtract
}
from
'@/service/moduleDispatch/agent/extract'
;
export
type
MessageItemType
=
ChatCompletionRequestMessage
&
{
_id
?:
string
};
type
FastGptWebChatProps
=
{
...
...
@@ -337,7 +338,8 @@ export async function dispatchModules({
[
FlowModuleTypeEnum
.
answerNode
]:
dispatchAnswer
,
[
FlowModuleTypeEnum
.
chatNode
]:
dispatchChatCompletion
,
[
FlowModuleTypeEnum
.
kbSearchNode
]:
dispatchKBSearch
,
[
FlowModuleTypeEnum
.
classifyQuestion
]:
dispatchClassifyQuestion
[
FlowModuleTypeEnum
.
classifyQuestion
]:
dispatchClassifyQuestion
,
[
FlowModuleTypeEnum
.
contentExtract
]:
dispatchContentExtract
};
if
(
callbackMap
[
module
.
flowType
])
{
return
callbackMap
[
module
.
flowType
](
props
);
...
...
client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeCQNode.tsx
View file @
58153306
...
...
@@ -10,7 +10,7 @@ import type { ClassifyQuestionAgentItemType } from '@/types/app';
import
{
customAlphabet
}
from
'nanoid'
;
const
nanoid
=
customAlphabet
(
'abcdefghijklmnopqrstuvwxyz1234567890'
,
4
);
import
MyIcon
from
'@/components/Icon'
;
import
{
FlowOutputItemTypeEnum
,
FlowValueTypeEnum
}
from
'@/constants/flow'
;
import
{
FlowOutputItemTypeEnum
,
FlowValueTypeEnum
,
SpecialInputKeyEnum
}
from
'@/constants/flow'
;
import
SourceHandle
from
'../render/SourceHandle'
;
const
NodeCQNode
=
({
...
...
@@ -25,7 +25,7 @@ const NodeCQNode = ({
onChangeNode=
{
onChangeNode
}
flowInputList=
{
inputs
}
CustomComponent=
{
{
agents
:
({
[
SpecialInputKeyEnum
.
agents
]
:
({
key
:
agentKey
,
value
:
agents
=
[]
}:
{
...
...
client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx
0 → 100644
View file @
58153306
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
;
client/src/pages/app/detail/components/AdEdit/components/modules/Divider.tsx
View file @
58153306
import
React
from
'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
{
t
}
=
useTranslation
();
return
(
<
Box
textAlign=
{
'center'
}
...
...
@@ -12,7 +14,7 @@ const Divider = ({ text }: { text: 'Body' | 'Input' | 'Output' | string }) => {
borderBottom=
{
theme
.
borders
.
base
}
fontSize=
{
'lg'
}
>
{
t
ext
}
{
t
(
`common.${text}`
)
}
</
Box
>
);
};
...
...
client/src/pages/app/detail/components/AdEdit/components/modules/ExtractFieldModal.tsx
0 → 100644
View file @
58153306
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
);
client/src/pages/app/detail/components/AdEdit/components/modules/NodeCard.tsx
View file @
58153306
...
...
@@ -29,7 +29,14 @@ const NodeCard = ({
const
theme
=
useTheme
();
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'
}
>
<
Avatar
src=
{
logo
}
borderRadius=
{
'md'
}
objectFit=
{
'contain'
}
w=
{
'30px'
}
h=
{
'30px'
}
/>
<
Box
ml=
{
3
}
fontSize=
{
'lg'
}
color=
{
'myGray.600'
}
>
...
...
@@ -39,7 +46,7 @@ const NodeCard = ({
<
MyTooltip
label=
{
description
}
forceShow
>
<
QuestionOutlineIcon
display=
{
[
'none'
,
'inline'
]
}
transform=
{
'translateY(
-
1px)'
}
transform=
{
'translateY(1px)'
}
ml=
{
1
}
/>
</
MyTooltip
>
...
...
client/src/pages/app/detail/components/AdEdit/index.tsx
View file @
58153306
...
...
@@ -68,6 +68,9 @@ const NodeVariable = dynamic(() => import('./components/Nodes/NodeVariable'), {
const
NodeUserGuide
=
dynamic
(()
=>
import
(
'./components/Nodes/NodeUserGuide'
),
{
ssr
:
false
});
const
NodeExtract
=
dynamic
(()
=>
import
(
'./components/Nodes/NodeExtract'
),
{
ssr
:
false
});
import
'reactflow/dist/style.css'
;
import
styles
from
'./index.module.scss'
;
...
...
@@ -83,7 +86,8 @@ const nodeTypes = {
[
FlowModuleTypeEnum
.
kbSearchNode
]:
NodeKbSearch
,
[
FlowModuleTypeEnum
.
tfSwitchNode
]:
NodeTFSwitch
,
[
FlowModuleTypeEnum
.
answerNode
]:
NodeAnswer
,
[
FlowModuleTypeEnum
.
classifyQuestion
]:
NodeCQNode
[
FlowModuleTypeEnum
.
classifyQuestion
]:
NodeCQNode
,
[
FlowModuleTypeEnum
.
contentExtract
]:
NodeExtract
// [FlowModuleTypeEnum.empty]: EmptyModule
};
const
edgeTypes
=
{
...
...
client/src/service/moduleDispatch/agent/classifyQuestion.ts
View file @
58153306
...
...
@@ -8,13 +8,14 @@ import { countModelPrice } from '@/service/events/pushBill';
import
{
UserModelSchema
}
from
'@/types/mongoSchema'
;
import
{
getModel
}
from
'@/service/utils/data'
;
import
{
SystemInputEnum
}
from
'@/constants/app'
;
import
{
SpecialInputKeyEnum
}
from
'@/constants/flow'
;
export
type
CQProps
=
{
systemPrompt
?:
string
;
history
?:
ChatItemType
[];
[
SystemInputEnum
.
userChatInput
]:
string
;
userOpenaiAccount
:
UserModelSchema
[
'openaiAccount'
];
agents
:
ClassifyQuestionAgentItemType
[];
[
SpecialInputKeyEnum
.
agents
]
:
ClassifyQuestionAgentItemType
[];
};
export
type
CQResponse
=
{
[
TaskResponseKeyEnum
.
responseData
]:
ChatHistoryItemResType
;
...
...
client/src/service/moduleDispatch/agent/extract.ts
View file @
58153306
// 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
{
ChatContextFilter
}
from
'@/service/utils/chat/index'
;
import
type
{
ChatItemType
}
from
'@/types/chat'
;
import
{
Chat
Role
Enum
}
from
'@/constants/chat'
;
import
type
{
Chat
HistoryItemResType
,
Chat
ItemType
}
from
'@/types/chat'
;
import
{
Chat
ModuleEnum
,
ChatRoleEnum
,
TaskResponseKey
Enum
}
from
'@/constants/chat'
;
import
{
getAIChatApi
,
axiosConfig
}
from
'@/service/ai/openai'
;
import
type
{
ClassifyQuestionAgentItemType
}
from
'@/types/app'
;
import
{
SystemInputEnum
}
from
'@/constants/app'
;
import
type
{
ContextExtractAgentItemType
}
from
'@/types/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
=
{
systemPrompt
?:
string
;
userOpenaiAccount
:
UserModelSchema
[
'openaiAccount'
]
;
history
?:
ChatItemType
[];
[
SystemInputEnum
.
userChatInpu
t
]:
string
;
description
:
string
;
agents
:
ClassifyQuestionAgentItemType
[]
;
[
ContextExtractEnum
.
conten
t
]:
string
;
[
ContextExtractEnum
.
extractKeys
]:
ContextExtractAgentItemType
[]
;
[
ContextExtractEnum
.
description
]:
string
;
};
export
type
Response
=
{
arguments
:
Record
<
string
,
any
>
;
deficiency
:
boolean
;
[
ContextExtractEnum
.
success
]?:
boolean
;
[
ContextExtractEnum
.
failed
]?:
boolean
;
[
ContextExtractEnum
.
fields
]:
Record
<
string
,
any
>
;
[
TaskResponseKeyEnum
.
responseData
]:
ChatHistoryItemResType
;
};
const
agentModel
=
'gpt-3.5-turbo'
;
const
agentFunName
=
'agent_extract_data'
;
const
maxTokens
=
3000
;
export
async
function
extract
({
systemPrompt
,
agents
,
export
async
function
dispatchContentExtract
({
userOpenaiAccount
,
content
,
extractKeys
,
history
=
[],
userChatInput
,
description
}:
Props
):
Promise
<
Response
>
{
const
messages
:
ChatItemType
[]
=
[
...(
systemPrompt
?
[
{
obj
:
ChatRoleEnum
.
System
,
value
:
systemPrompt
}
]
:
[]),
...
history
,
{
obj
:
ChatRoleEnum
.
Human
,
value
:
userChatInpu
t
value
:
conten
t
}
];
const
filterMessages
=
ChatContextFilter
({
...
...
@@ -62,25 +56,25 @@ export async function extract({
description
:
string
;
}
>
=
{};
agent
s
.
forEach
((
item
)
=>
{
extractKey
s
.
forEach
((
item
)
=>
{
properties
[
item
.
key
]
=
{
type
:
'string'
,
description
:
item
.
value
description
:
item
.
desc
};
});
// function body
const
agentFunction
=
{
name
:
agentFunName
,
description
,
description
:
`
${
description
}
\n如果内容不存在,返回空字符串。当前时间是2023/7/31 18:00`
,
parameters
:
{
type
:
'object'
,
properties
,
required
:
agent
s
.
map
((
item
)
=>
item
.
key
)
required
:
extractKey
s
.
map
((
item
)
=>
item
.
key
)
}
};
const
chatAPI
=
getAIChatApi
();
const
chatAPI
=
getAIChatApi
(
userOpenaiAccount
);
const
response
=
await
chatAPI
.
createChatCompletion
(
{
...
...
@@ -91,21 +85,44 @@ export async function extract({
functions
:
[
agentFunction
]
},
{
...
axiosConfig
()
...
axiosConfig
(
userOpenaiAccount
)
}
);
const
arg
=
JSON
.
parse
(
response
.
data
.
choices
?.[
0
]?.
message
?.
function_call
?.
arguments
||
'{}'
);
let
deficiency
=
false
;
for
(
const
key
in
arg
)
{
if
(
arg
[
key
]
===
''
)
{
deficiency
=
true
;
break
;
const
arg
:
Record
<
string
,
any
>
=
(()
=>
{
try
{
return
JSON
.
parse
(
response
.
data
.
choices
?.[
0
]?.
message
?.
function_call
?.
arguments
||
'{}'
);
}
catch
(
error
)
{
return
{};
}
})();
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
{
arguments
:
arg
,
deficiency
[
ContextExtractEnum
.
success
]:
success
?
true
:
undefined
,
[
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
}
};
}
client/src/types/app.d.ts
View file @
58153306
...
...
@@ -8,6 +8,7 @@ import {
import
type
{
FlowInputItemType
,
FlowOutputItemType
,
FlowOutputTargetItemType
}
from
'./flow'
;
import
type
{
AppSchema
,
kbSchema
}
from
'./mongoSchema'
;
import
{
ChatModelType
}
from
'@/constants/model'
;
import
{
FlowValueTypeEnum
}
from
'@/constants/flow'
;
export
type
AppListItemType
=
{
_id
:
string
;
...
...
@@ -45,6 +46,11 @@ export type ClassifyQuestionAgentItemType = {
value
:
string
;
key
:
string
;
};
export
type
ContextExtractAgentItemType
=
{
desc
:
string
;
key
:
string
;
required
:
boolean
;
};
export
type
VariableItemType
=
{
id
:
string
;
...
...
client/src/types/chat.d.ts
View file @
58153306
...
...
@@ -66,4 +66,8 @@ export type ChatHistoryItemResType = {
// cq
cqList
?:
ClassifyQuestionAgentItemType
[];
cqResult
?:
string
;
// content extract
extractDescription
?:
string
;
extractResult
?:
Record
<
string
,
any
>
;
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment