Skip to content

Commit 1e48922

Browse files
authored
Context extract support value type (FlowiseAI#1620)
* perf: chat box components * perf: chatbox context * feat: extract support value type * workflow performance * update doc * feat: error response * feat: error response * oauth sort * perf: logo * fix: update laf account * perf: team permission api * update type
1 parent 8ba8488 commit 1e48922

File tree

48 files changed

+232
-178
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+232
-178
lines changed

docSite/content/docs/development/openapi/chat.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ data: {"id":"","object":"","created":0,"choices":[{"delta":{"content":"《"},"in
211211
{{< markdownify >}}
212212

213213
```bash
214-
event: moduleStatus
214+
event: flowNodeStatus
215215
data: {"status":"running","name":"知识库搜索"}
216216

217-
event: moduleStatus
217+
event: flowNodeStatus
218218
data: {"status":"running","name":"AI 对话"}
219219

220220
event: answer
@@ -238,7 +238,7 @@ data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{},"index"
238238
event: answer
239239
data: [DONE]
240240

241-
event: appStreamResponse
241+
event: flowResponses
242242
data: [{"moduleName":"知识库搜索","moduleType":"datasetSearchNode","runningTime":1.78},{"question":"导演是谁","quoteList":[{"id":"654f2e49b64caef1d9431e8b","q":"电影《铃芽之旅》的导演是谁?","a":"电影《铃芽之旅》的导演是新海诚!","indexes":[{"type":"qa","dataId":"3515487","text":"电影《铃芽之旅》的导演是谁?","_id":"654f2e49b64caef1d9431e8c","defaultIndex":true}],"datasetId":"646627f4f7b896cfd8910e38","collectionId":"653279b16cd42ab509e766e8","sourceName":"data (81).csv","sourceId":"64fd3b6423aa1307b65896f6","score":0.8935586214065552},{"id":"6552e14c50f4a2a8e632af11","q":"导演是谁?","a":"电影《铃芽之旅》的导演是新海诚。","indexes":[{"defaultIndex":true,"type":"qa","dataId":"3644565","text":"导演是谁?\n电影《铃芽之旅》的导演是新海诚。","_id":"6552e14dde5cc7ba3954e417"}],"datasetId":"646627f4f7b896cfd8910e38","collectionId":"653279b16cd42ab509e766e8","sourceName":"data (81).csv","sourceId":"64fd3b6423aa1307b65896f6","score":0.8890955448150635},{"id":"654f34a0b64caef1d946337e","q":"本作的主人公是谁?","a":"本作的主人公是名叫铃芽的少女。","indexes":[{"type":"qa","dataId":"3515541","text":"本作的主人公是谁?","_id":"654f34a0b64caef1d946337f","defaultIndex":true}],"datasetId":"646627f4f7b896cfd8910e38","collectionId":"653279b16cd42ab509e766e8","sourceName":"data (81).csv","sourceId":"64fd3b6423aa1307b65896f6","score":0.8738770484924316},{"id":"654f3002b64caef1d944207a","q":"电影《铃芽之旅》男主角是谁?","a":"电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。","indexes":[{"type":"qa","dataId":"3515538","text":"电影《铃芽之旅》男主角是谁?","_id":"654f3002b64caef1d944207b","defaultIndex":true}],"datasetId":"646627f4f7b896cfd8910e38","collectionId":"653279b16cd42ab509e766e8","sourceName":"data (81).csv","sourceId":"64fd3b6423aa1307b65896f6","score":0.8607980012893677},{"id":"654f2fc8b64caef1d943fd46","q":"电影《铃芽之旅》的编剧是谁?","a":"新海诚是本片的编剧。","indexes":[{"defaultIndex":true,"type":"qa","dataId":"3515550","text":"电影《铃芽之旅》的编剧是谁?22","_id":"654f2fc8b64caef1d943fd47"}],"datasetId":"646627f4f7b896cfd8910e38","collectionId":"653279b16cd42ab509e766e8","sourceName":"data (81).csv","sourceId":"64fd3b6423aa1307b65896f6","score":0.8468944430351257}],"moduleName":"AI 对话","moduleType":"chatNode","runningTime":1.86}]
243243
```
244244

docSite/content/docs/development/upgrading/482.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ SANDBOX_URL=内网地址
2929
## V4.8.2 更新说明
3030

3131
1. 新增 - js代码运行节点(更完整的type提醒,后续继续完善)
32-
2. 修复 - 新增的站点同步无法使用
33-
3. 修复 - 定时任务无法输入内容
32+
2. 新增 - 内容提取节点支持数据类型选择
33+
3. 修复 - 新增的站点同步无法使用
34+
4. 修复 - 定时任务无法输入内容

packages/global/core/ai/prompt/agent.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,26 @@ A2:
2424
`
2525
};
2626

27-
export const Prompt_ExtractJson = `你可以从 <对话记录></对话记录> 中提取指定 JSON 信息,你仅需返回 JSON 字符串,无需回答问题。
27+
export const Prompt_ExtractJson = `你可以从 <对话记录></对话记录> 中提取指定 Json 信息,你仅需返回 Json 字符串,无需回答问题。
2828
<提取要求>
2929
{{description}}
3030
</提取要求>
3131
32-
<字段说明>
33-
1. 下面的 JSON 字符串均按照 JSON Schema 的规则描述。
34-
2. key 代表字段名;description 代表字段的描述;enum 是可选值,代表可选的 value。
35-
3. 如果没有可提取的内容,忽略该字段。
36-
4. 本次需提取的JSON Schema:{{json}}
37-
</字段说明>
32+
<提取规则>
33+
- 本次需提取的 json 字符串,需符合 JsonSchema 的规则。
34+
- type 代表数据类型; key 代表字段名; description 代表字段的描述; enum 是枚举值,代表可选的 value。
35+
- 如果没有可提取的内容,忽略该字段。
36+
</提取规则>
37+
38+
<JsonSchema>
39+
{{json}}
40+
</JsonSchema>
3841
3942
<对话记录>
4043
{{text}}
4144
</对话记录>
42-
`;
45+
46+
提取的 json 字符串:`;
4347

4448
export const Prompt_CQJson = `请帮我执行一个“问题分类”任务,将问题分类为以下几种类型之一:
4549

packages/global/core/workflow/runtime/type.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type DispatchNodeResponseType = {
3131
runningTime?: number;
3232
query?: string;
3333
textOutput?: string;
34+
error?: Record<string, any>;
3435
customInputs?: Record<string, any>;
3536
customOutputs?: Record<string, any>;
3637

packages/global/core/workflow/template/system/contextExtract.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export const ContextExtractModule: FlowNodeTemplateType = {
5656
label: '',
5757
valueType: WorkflowIOValueTypeEnum.any,
5858
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
59-
value: [] // {desc: string; key: string; required: boolean; enum: string[]}[]
59+
value: [] // {valueType: string; desc: string; key: string; required: boolean; enum: string[]}[]
6060
}
6161
],
6262
outputs: [

packages/global/core/workflow/type/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export type ClassifyQuestionAgentItemType = {
115115
key: string;
116116
};
117117
export type ContextExtractAgentItemType = {
118+
valueType: 'string' | 'number' | 'boolean';
118119
desc: string;
119120
key: string;
120121
required: boolean;

packages/global/support/user/team/controller.d.ts

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export type CreateTeamProps = {
1414
lafAccount?: LafAccountType;
1515
};
1616
export type UpdateTeamProps = {
17-
teamId: string;
1817
name?: string;
1918
avatar?: string;
2019
teamDomain?: string;

packages/global/support/wallet/bill/type.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type BillSchemaType = {
1111
status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED';
1212
type: `${BillTypeEnum}`;
1313
price: number;
14+
hasInvoice: boolean;
1415
metadata: {
1516
payWay: `${BillPayWayEnum}`;
1617
subMode?: `${SubModeEnum}`;
@@ -20,7 +21,6 @@ export type BillSchemaType = {
2021
extraPoints?: number;
2122
invoice: boolean;
2223
};
23-
username: string;
2424
};
2525

2626
export type ChatNodeUsageType = {

packages/service/core/workflow/dispatch/agent/extract.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ ${description ? `- ${description}` : ''}
183183
> = {};
184184
extractKeys.forEach((item) => {
185185
properties[item.key] = {
186-
type: 'string',
186+
type: item.valueType || 'string',
187187
description: item.desc,
188188
...(item.enum ? { enum: item.enum.split('\n') } : {})
189189
};
@@ -198,7 +198,7 @@ ${description ? `- ${description}` : ''}
198198
required: []
199199
}
200200
};
201-
201+
console.log(properties);
202202
return {
203203
filterMessages,
204204
agentFunction
@@ -319,12 +319,16 @@ const completions = async ({
319319
content: replaceVariable(extractModel.customExtractPrompt || Prompt_ExtractJson, {
320320
description,
321321
json: extractKeys
322-
.map(
323-
(item) =>
324-
`{"key":"${item.key}", "description":"${item.desc}"${
325-
item.enum ? `, "enum":"[${item.enum.split('\n')}]"` : ''
326-
}}`
327-
)
322+
.map((item) => {
323+
const valueType = item.valueType || 'string';
324+
if (valueType !== 'string' && valueType !== 'number') {
325+
item.enum = undefined;
326+
}
327+
328+
return `{"type":${item.valueType || 'string'}, "key":"${item.key}", "description":"${item.desc}" ${
329+
item.enum ? `, "enum":"[${item.enum.split('\n')}]"` : ''
330+
}}`;
331+
})
328332
.join('\n'),
329333
text: `${histories.map((item) => `${item.obj}:${chatValue2RuntimePrompt(item.value).text}`).join('\n')}
330334
Human: ${content}`
@@ -365,6 +369,7 @@ Human: ${content}`
365369
arg: json5.parse(jsonStr) as Record<string, any>
366370
};
367371
} catch (error) {
372+
console.log('Extract error, ai answer:', answer);
368373
console.log(error);
369374
return {
370375
rawResponse: answer,

packages/service/core/workflow/dispatch/code/run.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ export const dispatchRunCode = async (props: RunCodeType): Promise<RunCodeRespon
4545
}
4646
} catch (error) {
4747
return {
48-
[NodeOutputKeyEnum.error]: formatHttpError(error)
48+
[NodeOutputKeyEnum.error]: formatHttpError(error),
49+
[DispatchNodeResponseKeyEnum.nodeResponse]: {
50+
customInputs: customVariables,
51+
error: formatHttpError(error)
52+
}
4953
};
5054
}
5155
};

packages/service/support/permission/auth/user.ts

+17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
55
import { parseHeaderCert } from '../controller';
66
import { getTmbInfoByTmbId } from '../../user/team/controller';
77
import { UserErrEnum } from '../../../../global/common/error/code/user';
8+
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
89

910
export async function authUserNotVisitor(props: AuthModeType): Promise<
1011
AuthResponseType & {
@@ -47,3 +48,19 @@ export async function authUserRole(props: AuthModeType): Promise<
4748
canWrite
4849
};
4950
}
51+
52+
/* auth teamMember in team role */
53+
export async function authTeamOwner(props: AuthModeType): Promise<
54+
AuthResponseType & {
55+
role: `${TeamMemberRoleEnum}`;
56+
teamOwner: boolean;
57+
}
58+
> {
59+
const authRes = await authUserRole(props);
60+
61+
if (authRes.role !== TeamMemberRoleEnum.owner) {
62+
return Promise.reject(TeamErrEnum.unAuthTeam);
63+
}
64+
65+
return authRes;
66+
}

packages/service/support/user/team/controller.ts

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
} from '@fastgpt/global/support/user/team/constant';
88
import { MongoTeamMember } from './teamMemberSchema';
99
import { MongoTeam } from './teamSchema';
10+
import { UpdateTeamProps } from '@fastgpt/global/support/user/team/controller';
1011

1112
async function getTeamMember(match: Record<string, any>): Promise<TeamItemType> {
1213
const tmb = (await MongoTeamMember.findOne(match).populate('teamId')) as TeamMemberWithTeamSchema;
@@ -108,3 +109,18 @@ export async function createDefaultTeam({
108109
});
109110
}
110111
}
112+
113+
export async function updateTeam({
114+
teamId,
115+
name,
116+
avatar,
117+
teamDomain,
118+
lafAccount
119+
}: UpdateTeamProps & { teamId: string }) {
120+
await MongoTeam.findByIdAndUpdate(teamId, {
121+
name,
122+
avatar,
123+
teamDomain,
124+
lafAccount
125+
});
126+
}

packages/web/hooks/useConfirm.tsx

+9-10
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,17 @@ export const useConfirm = (props?: {
4444
const confirmCb = useRef<Function>();
4545
const cancelCb = useRef<any>();
4646

47-
const openConfirm = (
48-
confirm?: Function,
49-
cancel?: any,
50-
customContent?: string | React.ReactNode
51-
) => {
52-
confirmCb.current = confirm;
53-
cancelCb.current = cancel;
47+
const openConfirm = useCallback(
48+
(confirm?: Function, cancel?: any, customContent?: string | React.ReactNode) => {
49+
confirmCb.current = confirm;
50+
cancelCb.current = cancel;
5451

55-
customContent && setCustomContent(customContent);
52+
customContent && setCustomContent(customContent);
5653

57-
return onOpen;
58-
};
54+
return onOpen;
55+
},
56+
[]
57+
);
5958

6059
const ConfirmModal = useCallback(
6160
({

projects/app/i18n/en/common.json

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"App": "App",
44
"Code editor": "Code edit",
55
"Export": "Export",
6+
"Field name": "Name",
67
"Folder": "Folder",
78
"Is open": "Opened",
89
"Login": "Login",

projects/app/i18n/en/workflow.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"response": {
99
"Custom inputs": "Custom inputs",
10-
"Custom outputs": "Custom outputs"
10+
"Custom outputs": "Custom outputs",
11+
"Error": "Error"
1112
}
1213
}

projects/app/i18n/zh/common.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"App": "应用",
44
"Code editor": "代码编辑",
55
"Export": "导出",
6+
"Field name": "字段名",
67
"Folder": "文件夹",
78
"Is open": "是否开启",
89
"Login": "登录",
@@ -476,7 +477,7 @@
476477
"context total length": "上下文总长度",
477478
"module cq": "问题分类列表",
478479
"module cq result": "分类结果",
479-
"module extract description": "提取要求描述",
480+
"module extract description": "提取背景描述",
480481
"module extract result": "提取结果",
481482
"module historyPreview": "完整记录",
482483
"module http body": "请求体",
@@ -584,8 +585,7 @@
584585
"success": "开始同步"
585586
}
586587
},
587-
"training": {
588-
}
588+
"training": {}
589589
},
590590
"data": {
591591
"Auxiliary Data": "辅助数据",

projects/app/i18n/zh/workflow.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"response": {
99
"Custom inputs": "自定义输入",
10-
"Custom outputs": "自定义输出"
10+
"Custom outputs": "自定义输出",
11+
"Error": "错误信息"
1112
}
1213
}

projects/app/src/components/ChatBox/Input/ChatInput.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ import MyTooltip from '../../MyTooltip';
77
import MyIcon from '@fastgpt/web/components/common/Icon';
88
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
99
import { compressImgFileAndUpload } from '@/web/common/file/controller';
10-
import { customAlphabet } from 'nanoid';
1110
import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants';
1211
import { addDays } from 'date-fns';
1312
import { useRequest } from '@fastgpt/web/hooks/useRequest';
1413
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
1514
import { ChatBoxInputFormType, ChatBoxInputType, UserInputFileItemType } from '../type';
1615
import { textareaMinH } from '../constants';
1716
import { UseFormReturn, useFieldArray } from 'react-hook-form';
18-
import { useChatProviderStore } from '../Provider';
17+
import { ChatBoxContext } from '../Provider';
1918
import dynamic from 'next/dynamic';
20-
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
19+
import { useContextSelector } from 'use-context-selector';
20+
import { getNanoid } from '@fastgpt/global/common/string/tools';
2121

2222
const InputGuideBox = dynamic(() => import('./InputGuideBox'));
2323

@@ -60,7 +60,7 @@ const ChatInput = ({
6060
whisperConfig,
6161
autoTTSResponse,
6262
chatInputGuide
63-
} = useChatProviderStore();
63+
} = useContextSelector(ChatBoxContext, (v) => v);
6464
const { isPc, whisperModel } = useSystemStore();
6565
const canvasRef = useRef<HTMLCanvasElement>(null);
6666
const { t } = useTranslation();
@@ -119,7 +119,7 @@ const ChatInput = ({
119119
reader.readAsDataURL(file);
120120
reader.onload = () => {
121121
const item = {
122-
id: nanoid(),
122+
id: getNanoid(6),
123123
rawFile: file,
124124
type: ChatFileTypeEnum.image,
125125
name: file.name,
@@ -132,7 +132,7 @@ const ChatInput = ({
132132
};
133133
} else {
134134
resolve({
135-
id: nanoid(),
135+
id: getNanoid(6),
136136
rawFile: file,
137137
type: ChatFileTypeEnum.file,
138138
name: file.name,

projects/app/src/components/ChatBox/Input/InputGuideBox.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { queryChatInputGuideList } from '@/web/core/chat/inputGuide/api';
77
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
88
import { useTranslation } from 'next-i18next';
99
import HighlightText from '@fastgpt/web/components/common/String/HighlightText';
10-
import { useChatProviderStore } from '../Provider';
10+
import { ChatBoxContext } from '../Provider';
11+
import { useContextSelector } from 'use-context-selector';
1112

1213
export default function InputGuideBox({
1314
appId,
@@ -22,7 +23,7 @@ export default function InputGuideBox({
2223
}) {
2324
const { t } = useTranslation();
2425
const { chatT } = useI18n();
25-
const { chatInputGuide } = useChatProviderStore();
26+
const chatInputGuide = useContextSelector(ChatBoxContext, (v) => v.chatInputGuide);
2627

2728
const { data = [] } = useRequest2(
2829
async () => {

projects/app/src/components/ChatBox/MarkModal.tsx

-16
This file was deleted.

0 commit comments

Comments
 (0)