4.8.6 merge (#1943)

* Dataset collection forbid (#1885)

* perf: tool call support same id

* feat: collection forbid

* feat: collection forbid

* Inheritance Permission for apps (#1897)

* feat: app schema define

chore: references of authapp

* feat: authApp method inheritance

* feat: create and update api

* feat: update

* feat: inheritance Permission controller for app.

* feat: abstract version of inheritPermission

* feat: ancestorId for apps

* chore: update app

* fix: inheritPermission abstract version

* feat: update folder defaultPermission

* feat: app update api

* chore: inheritance frontend

* chore: app list api

* feat: update defaultPermission in app deatil

* feat: backend api finished

* feat: app inheritance permission fe

* fix: app update defaultpermission causes collaborator miss

* fix: ts error

* chore: adjust the codes

* chore: i18n

chore: i18n

* chore: fe adjust and i18n

* chore: adjust the code

* feat: resume api;
chore: rewrite update api and inheritPermission methods

* chore: something

* chore: fe code adjusting

* feat: frontend adjusting

* chore: fe code adjusting

* chore: adjusting the code

* perf: fe loading

* format

* Inheritance fix (#1908)

* fix: SlideCard

* fix: authapp did not return parent app for inheritance app

* fix: fe adjusting

* feat: fe adjusing

* perf: inherit per ux

* doc

* fix: ts errors (#1916)

* perf: inherit permission

* fix: permission inherit

* Workflow type (#1938)

* perf: workflow type

tmp workflow

perf: workflow type

feat: custom field config

* perf: dynamic input

* perf: node classify

* perf: node classify

* perf: node classify

* perf: node classify

* fix: workflow custom input

* feat: text editor and customFeedback move to basic nodes

* feat: community system plugin

* fix: ts

* feat: exprEval plugin

* perf: workflow type

* perf: plugin important

* fix: default templates

* perf: markdown hr css

* lock

* perf: fetch url

* perf: new plugin version

* fix: chat histories update

* fix: collection paths invalid

* perf: app card ui

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
Archer 2024-07-04 17:42:09 +08:00 committed by GitHub
parent babf03c218
commit a9cdece341
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
303 changed files with 18883 additions and 13149 deletions

View File

@ -120,7 +120,7 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
## 🏘️ 社区交流群 ## 🏘️ 社区交流群
扫码加入飞书话题群(新开,逐渐弃用微信群) 扫码加入飞书话题群 (新开,逐渐弃用微信群)
![](https://oss.laf.run/otnvvf-imgs/1719505774252.jpg) ![](https://oss.laf.run/otnvvf-imgs/1719505774252.jpg)

View File

@ -0,0 +1,42 @@
---
title: 'V4.8.6(进行中)'
description: 'FastGPT V4.8.6 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 818
---
## 升级指南
### 1. 做好数据库备份
### 2. 修改镜像
- fastgpt 镜像 tag 修改成 v4.8.6-alpha
- fastgpt-sandbox 镜像 tag 修改成 v4.8.6-alpha
- 商业版镜像 tag 修改成 v4.8.6-alpha
### 3. 执行初始化
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**FastGPT 域名**。
```bash
curl --location --request POST 'https://{{host}}/api/admin/initv486' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
会初始化应用的继承权限
-------
## V4.8.6 更新说明
1. 新增 - 知识库支持单个集合禁用功能
2. 新增 - 文件夹权限继承
3. 新增 - 网页抓取和数学计算器系统插件
4. 新增 - 移动文本加工和自定义反馈到基础节点中
5. 优化 - Read file 默认选中从节点,实现 MongoDB 读写分离,减轻主节点压力
6. 修复 - 工作流中团队插件加载异常
7. 修复 - 知识库集合目录导航失效

View File

@ -201,7 +201,7 @@ weight: 404
"x": 1623.9214305901633, "x": 1623.9214305901633,
"y": 22.777089001645862 "y": 22.777089001645862
}, },
"version": "481", "version": "486",
"inputs": [ "inputs": [
{ {
"key": "system_addInputParam", "key": "system_addInputParam",

View File

@ -192,7 +192,7 @@ export default async function (ctx: FunctionContext) {
}, },
{ {
"nodeId": "NOgbnBzUwDgT", "nodeId": "NOgbnBzUwDgT",
"name": "工具调用(实验)", "name": "工具调用",
"intro": "通过AI模型自动选择一个或多个功能块进行调用也可以对插件进行调用。", "intro": "通过AI模型自动选择一个或多个功能块进行调用也可以对插件进行调用。",
"avatar": "/imgs/workflow/tool.svg", "avatar": "/imgs/workflow/tool.svg",
"flowNodeType": "tools", "flowNodeType": "tools",

View File

@ -436,7 +436,7 @@ HTTP模块中需要设置 3 个工具参数:
}, },
{ {
"nodeId": "fYxwWym8flYL", "nodeId": "fYxwWym8flYL",
"name": "工具调用(实验)", "name": "工具调用",
"intro": "通过AI模型自动选择一个或多个功能块进行调用也可以对插件进行调用。", "intro": "通过AI模型自动选择一个或多个功能块进行调用也可以对插件进行调用。",
"avatar": "/imgs/workflow/tool.svg", "avatar": "/imgs/workflow/tool.svg",
"flowNodeType": "tools", "flowNodeType": "tools",

View File

@ -5,7 +5,8 @@ const startCode = 507000;
export enum CommonErrEnum { export enum CommonErrEnum {
fileNotFound = 'fileNotFound', fileNotFound = 'fileNotFound',
unAuthFile = 'unAuthFile', unAuthFile = 'unAuthFile',
missingParams = 'missingParams' missingParams = 'missingParams',
inheritPermissionError = 'inheritPermissionError'
} }
const datasetErr = [ const datasetErr = [
{ {
@ -19,6 +20,10 @@ const datasetErr = [
{ {
statusText: CommonErrEnum.missingParams, statusText: CommonErrEnum.missingParams,
message: 'error.missingParams' message: 'error.missingParams'
},
{
statusText: CommonErrEnum.inheritPermissionError,
message: 'error.inheritPermissionError'
} }
]; ];
export default datasetErr.reduce((acc, cur, index) => { export default datasetErr.reduce((acc, cur, index) => {

View File

@ -1,6 +1,7 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import cronParser from 'cron-parser'; import cronParser from 'cron-parser';
export const formatTime2YMDHMW = (time?: Date) => dayjs(time).format('YYYY-MM-DD HH:mm:ss dddd');
export const formatTime2YMDHM = (time?: Date) => export const formatTime2YMDHM = (time?: Date) =>
time ? dayjs(time).format('YYYY-MM-DD HH:mm') : ''; time ? dayjs(time).format('YYYY-MM-DD HH:mm') : '';
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : ''); export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');

View File

@ -8,6 +8,8 @@ export enum AppTypeEnum {
httpPlugin = 'httpPlugin' httpPlugin = 'httpPlugin'
} }
export const AppFolderTypeList = [AppTypeEnum.folder, AppTypeEnum.httpPlugin];
export const defaultTTSConfig: AppTTSConfigType = { type: 'web' }; export const defaultTTSConfig: AppTTSConfigType = { type: 'web' };
export const defaultWhisperConfig: AppWhisperConfigType = { export const defaultWhisperConfig: AppWhisperConfigType = {

View File

@ -4,12 +4,12 @@ import yaml from 'js-yaml';
import { OpenAPIV3 } from 'openapi-types'; import { OpenAPIV3 } from 'openapi-types';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../../workflow/type/io'; import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../../workflow/type/io';
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../../workflow/node/constant'; import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../../workflow/node/constant';
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '../../workflow/constants'; import { WorkflowIOValueTypeEnum } from '../../workflow/constants';
import { PluginInputModule } from '../../workflow/template/system/pluginInput'; import { PluginInputModule } from '../../workflow/template/system/pluginInput';
import { PluginOutputModule } from '../../workflow/template/system/pluginOutput'; import { PluginOutputModule } from '../../workflow/template/system/pluginOutput';
import { HttpModule468 } from '../../workflow/template/system/http468'; import { HttpNode468 } from '../../workflow/template/system/http468';
import { HttpParamAndHeaderItemType } from '../../workflow/api'; import { HttpParamAndHeaderItemType } from '../../workflow/api';
import { StoreNodeItemType } from '../../workflow/type'; import { StoreNodeItemType } from '../../workflow/type/node';
import { HttpImgUrl } from '../../../common/file/image/constants'; import { HttpImgUrl } from '../../../common/file/image/constants';
import SwaggerParser from '@apidevtools/swagger-parser'; import SwaggerParser from '@apidevtools/swagger-parser';
import { getHandleId } from '../../workflow/utils'; import { getHandleId } from '../../workflow/utils';
@ -116,16 +116,7 @@ export const httpApiSchema2Plugins = async ({
required: param.required, required: param.required,
description: param.description, description: param.description,
toolDescription: param.description, toolDescription: param.description,
canEdit: true, canEdit: true
editField: {
key: true,
name: true,
description: true,
required: true,
dataType: true,
inputType: true,
isToolInput: true
}
}; };
}) || []), }) || []),
...(propsKeys?.map((key) => { ...(propsKeys?.map((key) => {
@ -138,16 +129,7 @@ export const httpApiSchema2Plugins = async ({
required: false, required: false,
description: prop.description, description: prop.description,
toolDescription: prop.description, toolDescription: prop.description,
canEdit: true, canEdit: true
editField: {
key: true,
name: true,
description: true,
required: true,
dataType: true,
inputType: true,
isToolInput: true
}
}; };
}) || []) }) || [])
]; ];
@ -186,10 +168,6 @@ export const httpApiSchema2Plugins = async ({
label: param.name, label: param.name,
renderTypeList: [FlowNodeInputTypeEnum.reference], renderTypeList: [FlowNodeInputTypeEnum.reference],
canEdit: true, canEdit: true,
editField: {
key: true,
valueType: true
},
value: [pluginInputId, inputIdMap.get(param.name)] value: [pluginInputId, inputIdMap.get(param.name)]
}; };
}) || []), }) || []),
@ -200,10 +178,6 @@ export const httpApiSchema2Plugins = async ({
label: key, label: key,
renderTypeList: [FlowNodeInputTypeEnum.reference], renderTypeList: [FlowNodeInputTypeEnum.reference],
canEdit: true, canEdit: true,
editField: {
key: true,
valueType: true
},
value: [pluginInputId, inputIdMap.get(key)] value: [pluginInputId, inputIdMap.get(key)]
}; };
}) || []) }) || [])
@ -271,7 +245,7 @@ export const httpApiSchema2Plugins = async ({
} }
/* Combine complete modules */ /* Combine complete modules */
const modules: StoreNodeItemType[] = [ const nodes: StoreNodeItemType[] = [
{ {
nodeId: pluginInputId, nodeId: pluginInputId,
name: PluginInputModule.name, name: PluginInputModule.name,
@ -280,8 +254,8 @@ export const httpApiSchema2Plugins = async ({
flowNodeType: PluginInputModule.flowNodeType, flowNodeType: PluginInputModule.flowNodeType,
showStatus: PluginInputModule.showStatus, showStatus: PluginInputModule.showStatus,
position: { position: {
x: 616.4226348688949, x: 473.55206291900333,
y: -165.05298493910115 y: -145.65080850146154
}, },
version: PluginInputModule.version, version: PluginInputModule.version,
inputs: pluginInputs, inputs: pluginInputs,
@ -295,8 +269,8 @@ export const httpApiSchema2Plugins = async ({
flowNodeType: PluginOutputModule.flowNodeType, flowNodeType: PluginOutputModule.flowNodeType,
showStatus: PluginOutputModule.showStatus, showStatus: PluginOutputModule.showStatus,
position: { position: {
x: 1607.7142331269126, x: 1847.5956872650024,
y: -151.8669210746189 y: 5.114324648101558
}, },
version: PluginOutputModule.version, version: PluginOutputModule.version,
inputs: [ inputs: [
@ -308,11 +282,6 @@ export const httpApiSchema2Plugins = async ({
required: false, required: false,
description: '', description: '',
canEdit: true, canEdit: true,
editField: {
key: true,
description: true,
valueType: true
},
value: [httpId, 'httpRawResponse'] value: [httpId, 'httpRawResponse']
} }
], ],
@ -328,29 +297,18 @@ export const httpApiSchema2Plugins = async ({
}, },
{ {
nodeId: httpId, nodeId: httpId,
name: HttpModule468.name, name: HttpNode468.name,
intro: HttpModule468.intro, intro: HttpNode468.intro,
avatar: HttpModule468.avatar, avatar: HttpNode468.avatar,
flowNodeType: HttpModule468.flowNodeType, flowNodeType: HttpNode468.flowNodeType,
showStatus: true, showStatus: true,
position: { position: {
x: 1042.549746602742, x: 1188.947986995841,
y: -447.77496332641647 y: -473.52694296182904
}, },
version: HttpModule468.version, version: HttpNode468.version,
inputs: [ inputs: [
{ HttpNode468.inputs[0],
key: NodeInputKeyEnum.addInputParam,
renderTypeList: [FlowNodeInputTypeEnum.addInputParam],
valueType: WorkflowIOValueTypeEnum.dynamic,
label: '',
required: false,
description: 'core.module.input.description.HTTP Dynamic Input',
editField: {
key: true,
valueType: true
}
},
...httpInputs, ...httpInputs,
{ {
key: 'system_httpMethod', key: 'system_httpMethod',
@ -397,7 +355,7 @@ export const httpApiSchema2Plugins = async ({
required: false required: false
} }
], ],
outputs: HttpModule468.outputs outputs: HttpNode468.outputs
} }
]; ];
@ -422,7 +380,7 @@ export const httpApiSchema2Plugins = async ({
intro: item.description, intro: item.description,
parentId, parentId,
type: AppTypeEnum.plugin, type: AppTypeEnum.plugin,
modules, modules: nodes,
edges, edges,
pluginData: { pluginData: {
pluginUniId: item.name pluginUniId: item.name

View File

@ -1,4 +1,4 @@
import type { FlowNodeTemplateType, StoreNodeItemType } from '../workflow/type'; import type { FlowNodeTemplateType, StoreNodeItemType } from '../workflow/type/node';
import { AppTypeEnum } from './constants'; import { AppTypeEnum } from './constants';
import { PermissionTypeEnum } from '../../support/permission/constant'; import { PermissionTypeEnum } from '../../support/permission/constant';
import { VariableInputEnum } from '../workflow/constants'; import { VariableInputEnum } from '../workflow/constants';
@ -6,7 +6,7 @@ import { SelectedDatasetType } from '../workflow/api';
import { DatasetSearchModeEnum } from '../dataset/constants'; import { DatasetSearchModeEnum } from '../dataset/constants';
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d'; import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
import { StoreEdgeItemType } from '../workflow/type/edge'; import { StoreEdgeItemType } from '../workflow/type/edge';
import { PermissionValueType } from '../../support/permission/type'; import { PermissionSchemaType, PermissionValueType } from '../../support/permission/type';
import { AppPermission } from '../../support/permission/app/controller'; import { AppPermission } from '../../support/permission/app/controller';
import { ParentIdType } from '../../common/parentFolder/type'; import { ParentIdType } from '../../common/parentFolder/type';
@ -39,8 +39,7 @@ export type AppSchema = {
inited?: boolean; inited?: boolean;
teamTags: string[]; teamTags: string[];
defaultPermission: PermissionValueType; } & PermissionSchemaType;
};
export type AppListItemType = { export type AppListItemType = {
_id: string; _id: string;
@ -50,10 +49,9 @@ export type AppListItemType = {
intro: string; intro: string;
type: AppTypeEnum; type: AppTypeEnum;
updateTime: Date; updateTime: Date;
defaultPermission: PermissionValueType;
permission: AppPermission;
pluginData?: AppSchema['pluginData']; pluginData?: AppSchema['pluginData'];
}; permission: AppPermission;
} & PermissionSchemaType;
export type AppDetailType = AppSchema & { export type AppDetailType = AppSchema & {
permission: AppPermission; permission: AppPermission;

View File

@ -3,7 +3,7 @@ import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants'; import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants';
import type { FlowNodeInputItemType } from '../workflow/type/io.d'; import type { FlowNodeInputItemType } from '../workflow/type/io.d';
import { getAppChatConfig } from '../workflow/utils'; import { getAppChatConfig } from '../workflow/utils';
import { StoreNodeItemType } from '../workflow/type'; import { StoreNodeItemType } from '../workflow/type/node';
import { DatasetSearchModeEnum } from '../dataset/constants'; import { DatasetSearchModeEnum } from '../dataset/constants';
export const getDefaultAppForm = (): AppSimpleEditFormType => ({ export const getDefaultAppForm = (): AppSimpleEditFormType => ({

View File

@ -1,4 +1,3 @@
import { StoreNodeItemType } from '../workflow/type';
import { StoreEdgeItemType } from '../workflow/type/edge'; import { StoreEdgeItemType } from '../workflow/type/edge';
import { AppChatConfigType, AppSchema } from './type'; import { AppChatConfigType, AppSchema } from './type';

View File

@ -1,4 +1,4 @@
import { ClassifyQuestionAgentItemType } from '../workflow/type'; import { ClassifyQuestionAgentItemType } from '../workflow/template/system/classifyQuestion/type';
import { SearchDataResponseItemType } from '../dataset/type'; import { SearchDataResponseItemType } from '../dataset/type';
import { import {
ChatFileTypeEnum, ChatFileTypeEnum,

View File

@ -1,3 +1,4 @@
import { DatasetCollectionTypeEnum, TrainingModeEnum, TrainingTypeMap } from '../constants';
import { CollectionWithDatasetType, DatasetCollectionSchemaType } from '../type'; import { CollectionWithDatasetType, DatasetCollectionSchemaType } from '../type';
export const getCollectionSourceData = ( export const getCollectionSourceData = (
@ -12,3 +13,13 @@ export const getCollectionSourceData = (
sourceName: collection?.name || '' sourceName: collection?.name || ''
}; };
}; };
export const checkCollectionIsFolder = (type: DatasetCollectionTypeEnum) => {
return type === DatasetCollectionTypeEnum.folder || type === DatasetCollectionTypeEnum.virtual;
};
export const getTrainingTypeLabel = (type?: TrainingModeEnum) => {
if (!type) return '';
if (!TrainingTypeMap[type]) return '';
return TrainingTypeMap[type].label;
};

View File

@ -27,7 +27,7 @@ export type DatasetSchemaType = {
intro: string; intro: string;
type: DatasetTypeEnum; type: DatasetTypeEnum;
status: `${DatasetStatusEnum}`; status: `${DatasetStatusEnum}`;
permission: DatasetPermission; // permission: DatasetPermission;
// metadata // metadata
websiteConfig?: { websiteConfig?: {
@ -48,6 +48,7 @@ export type DatasetCollectionSchemaType = {
type: DatasetCollectionTypeEnum; type: DatasetCollectionTypeEnum;
createTime: Date; createTime: Date;
updateTime: Date; updateTime: Date;
forbid?: boolean;
trainingType: TrainingModeEnum; trainingType: TrainingModeEnum;
chunkSize: number; chunkSize: number;
@ -89,6 +90,7 @@ export type DatasetDataSchemaType = {
updateTime: Date; updateTime: Date;
q: string; // large chunks or question q: string; // large chunks or question
a: string; // answer or custom content a: string; // answer or custom content
forbid?: boolean;
fullTextToken: string; fullTextToken: string;
indexes: DatasetDataIndexItemType[]; indexes: DatasetDataIndexItemType[];
rebuilding?: boolean; rebuilding?: boolean;
@ -144,6 +146,7 @@ export type DatasetListItemType = {
export type DatasetItemType = Omit<DatasetSchemaType, 'vectorModel' | 'agentModel'> & { export type DatasetItemType = Omit<DatasetSchemaType, 'vectorModel' | 'agentModel'> & {
vectorModel: VectorModelItemType; vectorModel: VectorModelItemType;
agentModel: LLMModelItemType; agentModel: LLMModelItemType;
permission: DatasetPermission;
}; };
/* ================= collection ===================== */ /* ================= collection ===================== */

View File

@ -1,5 +1,3 @@
import { StoreNodeItemType } from '../workflow/type';
export enum PluginTypeEnum { export enum PluginTypeEnum {
folder = 'folder', folder = 'folder',
custom = 'custom', custom = 'custom',

View File

@ -1,5 +1,5 @@
import { StoreEdgeItemType } from 'core/workflow/type/edge'; import { StoreEdgeItemType } from 'core/workflow/type/edge';
import type { StoreNodeItemType } from '../workflow/type'; import type { StoreNodeItemType } from '../workflow/type/node';
import { PluginTypeEnum } from './constants'; import { PluginTypeEnum } from './constants';
import { HttpAuthMethodType } from '../app/httpPlugin/type'; import { HttpAuthMethodType } from '../app/httpPlugin/type';

View File

@ -1,8 +1,9 @@
import { StoreEdgeItemType } from 'core/workflow/type/edge'; import { StoreEdgeItemType } from 'core/workflow/type/edge';
import { ModuleTemplateTypeEnum } from '../workflow/constants'; import { ModuleTemplateTypeEnum } from '../workflow/constants';
import type { FlowModuleTemplateType, StoreNodeItemType } from '../workflow/type'; import type { StoreNodeItemType } from '../workflow/type/node';
import { PluginSourceEnum, PluginTypeEnum } from './constants'; import { PluginSourceEnum, PluginTypeEnum } from './constants';
import { MethodType } from './controller'; import { MethodType } from './controller';
import { FlowNodeTemplateType } from '../workflow/type/node';
export type PluginItemSchema = { export type PluginItemSchema = {
_id: string; _id: string;

View File

@ -4,7 +4,7 @@ import { NodeInputKeyEnum } from './constants';
export type SelectedDatasetType = { datasetId: string }[]; export type SelectedDatasetType = { datasetId: string }[];
export type HttpBodyType<T = Record<string, any>> = { export type HttpBodyType<T = Record<string, any>> = {
[NodeInputKeyEnum.addInputParam]: Record<string, any>; // [NodeInputKeyEnum.addInputParam]: Record<string, any>;
} & T; } & T;
export type HttpQueryType = { export type HttpQueryType = {
appId: string; appId: string;

View File

@ -1,13 +1,11 @@
export enum FlowNodeTemplateTypeEnum { export enum FlowNodeTemplateTypeEnum {
systemInput = 'systemInput', systemInput = 'systemInput',
ai = 'ai',
function = 'function',
tools = 'tools', tools = 'tools',
textAnswer = 'textAnswer',
functionCall = 'functionCall',
externalCall = 'externalCall',
personalPlugin = 'personalPlugin', other = 'other',
teamApp = 'teamApp'
other = 'other'
} }
export enum WorkflowIOValueTypeEnum { export enum WorkflowIOValueTypeEnum {
@ -84,6 +82,9 @@ export enum NodeInputKeyEnum {
datasetSearchExtensionModel = 'datasetSearchExtensionModel', datasetSearchExtensionModel = 'datasetSearchExtensionModel',
datasetSearchExtensionBg = 'datasetSearchExtensionBg', datasetSearchExtensionBg = 'datasetSearchExtensionBg',
// concat dataset
datasetQuoteList = 'system_datasetQuoteList',
// context extract // context extract
contextExtractInput = 'content', contextExtractInput = 'content',
extractKeys = 'extractKeys', extractKeys = 'extractKeys',
@ -180,8 +181,6 @@ export const variableMap = {
} }
}; };
export const DYNAMIC_INPUT_REFERENCE_KEY = 'DYNAMIC_INPUT_REFERENCE_KEY';
/* run time */ /* run time */
export enum RuntimeEdgeStatusEnum { export enum RuntimeEdgeStatusEnum {
'waiting' = 'waiting', 'waiting' = 'waiting',
@ -190,3 +189,4 @@ export enum RuntimeEdgeStatusEnum {
} }
export const VARIABLE_NODE_ID = 'VARIABLE_NODE_ID'; export const VARIABLE_NODE_ID = 'VARIABLE_NODE_ID';
export const DYNAMIC_INPUT_REFERENCE_KEY = 'DYNAMIC_INPUT_REFERENCE_KEY';

View File

@ -1,8 +1,11 @@
import { WorkflowIOValueTypeEnum } from '../constants';
export enum FlowNodeInputTypeEnum { // render ui export enum FlowNodeInputTypeEnum { // render ui
reference = 'reference', // reference to other node output reference = 'reference', // reference to other node output
input = 'input', // one line input input = 'input', // one line input
numberInput = 'numberInput', numberInput = 'numberInput',
switch = 'switch', // true/false switch = 'switch', // true/false
select = 'select',
// editor // editor
textarea = 'textarea', textarea = 'textarea',
@ -22,8 +25,6 @@ export enum FlowNodeInputTypeEnum { // render ui
selectDatasetParamsModal = 'selectDatasetParamsModal', selectDatasetParamsModal = 'selectDatasetParamsModal',
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt', settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
select = 'select',
hidden = 'hidden', hidden = 'hidden',
custom = 'custom' custom = 'custom'
} }
@ -114,8 +115,97 @@ export enum FlowNodeTypeEnum {
lafModule = 'lafModule', lafModule = 'lafModule',
ifElseNode = 'ifElseNode', ifElseNode = 'ifElseNode',
variableUpdate = 'variableUpdate', variableUpdate = 'variableUpdate',
code = 'code' code = 'code',
textEditor = 'textEditor',
customFeedback = 'customFeedback'
} }
// node IO value type
export const FlowValueTypeMap = {
[WorkflowIOValueTypeEnum.string]: {
label: 'string',
value: WorkflowIOValueTypeEnum.string,
description: ''
},
[WorkflowIOValueTypeEnum.number]: {
label: 'number',
value: WorkflowIOValueTypeEnum.number,
description: ''
},
[WorkflowIOValueTypeEnum.boolean]: {
label: 'boolean',
value: WorkflowIOValueTypeEnum.boolean,
description: ''
},
[WorkflowIOValueTypeEnum.object]: {
label: 'object',
value: WorkflowIOValueTypeEnum.object,
description: ''
},
[WorkflowIOValueTypeEnum.arrayString]: {
label: 'array<string>',
value: WorkflowIOValueTypeEnum.arrayString,
description: ''
},
[WorkflowIOValueTypeEnum.arrayNumber]: {
label: 'array<number>',
value: WorkflowIOValueTypeEnum.arrayNumber,
description: ''
},
[WorkflowIOValueTypeEnum.arrayBoolean]: {
label: 'array<boolean>',
value: WorkflowIOValueTypeEnum.arrayBoolean,
description: ''
},
[WorkflowIOValueTypeEnum.arrayObject]: {
label: 'array<object>',
value: WorkflowIOValueTypeEnum.arrayObject,
description: ''
},
[WorkflowIOValueTypeEnum.any]: {
label: 'any',
value: WorkflowIOValueTypeEnum.any,
description: ''
},
[WorkflowIOValueTypeEnum.chatHistory]: {
label: '历史记录',
value: WorkflowIOValueTypeEnum.chatHistory,
description: `{
obj: System | Human | AI;
value: string;
}[]`
},
[WorkflowIOValueTypeEnum.datasetQuote]: {
label: '知识库引用',
value: WorkflowIOValueTypeEnum.datasetQuote,
description: `{
id: string;
datasetId: string;
collectionId: string;
sourceName: string;
sourceId?: string;
q: string;
a: string
}[]`
},
[WorkflowIOValueTypeEnum.selectApp]: {
label: '选择应用',
value: WorkflowIOValueTypeEnum.selectApp,
description: ''
},
[WorkflowIOValueTypeEnum.selectDataset]: {
label: '选择知识库',
value: WorkflowIOValueTypeEnum.selectDataset,
description: `{
datasetId: string;
}`
},
[WorkflowIOValueTypeEnum.dynamic]: {
label: '动态输入',
value: WorkflowIOValueTypeEnum.dynamic,
description: ''
}
};
export const EDGE_TYPE = 'default'; export const EDGE_TYPE = 'default';
export const defaultNodeVersion = '481'; export const defaultNodeVersion = '481';

View File

@ -0,0 +1,17 @@
import { FlowNodeInputItemType } from '../../type/io';
export const getInputComponentProps = (input: FlowNodeInputItemType) => {
return {
referencePlaceholder: input.referencePlaceholder,
placeholder: input.placeholder,
maxLength: input.maxLength,
list: input.list,
markList: input.markList,
step: input.step,
max: input.max,
min: input.min,
defaultValue: input.defaultValue,
llmModelType: input.llmModelType,
customInputConfig: input.customInputConfig
};
};

View File

@ -1,39 +0,0 @@
/*
react flow type
*/
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './constant';
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants';
import { SelectedDatasetType } from '../api';
import { LLMModelTypeEnum } from '../../ai/constants';
/* --------------- edit field ------------------- */
export type EditInputFieldMapType = EditOutputFieldMapType & {
inputType?: boolean;
};
export type EditOutputFieldMapType = {
key?: boolean;
description?: boolean;
valueType?: boolean; // output
required?: boolean;
defaultValue?: boolean;
};
export type EditNodeFieldType = {
inputType?: FlowNodeInputTypeEnum; // input type
valueType?: WorkflowIOValueTypeEnum;
required?: boolean;
key?: string;
label?: string;
description?: string;
isToolInput?: boolean;
defaultValue?: string;
maxLength?: number;
max?: number;
min?: number;
editField?: EditInputFieldMapType;
dynamicParamDefaultValue?: {
inputType?: FlowNodeInputTypeEnum; // input type
valueType?: WorkflowIOValueTypeEnum;
required?: boolean;
};
};

View File

@ -1,11 +1,56 @@
import { ChatNodeUsageType } from '../../../support/wallet/bill/type'; import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import { ChatItemValueItemType, ToolRunResponseItemType } from '../../chat/type'; import {
ChatItemType,
UserChatItemValueItemType,
ChatItemValueItemType,
ToolRunResponseItemType
} from '../../chat/type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d'; import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
import { StoreNodeItemType } from '../type'; import { StoreNodeItemType } from '../type/node';
import { DispatchNodeResponseKeyEnum } from './constants'; import { DispatchNodeResponseKeyEnum } from './constants';
import { StoreEdgeItemType } from '../type/edge'; import { StoreEdgeItemType } from '../type/edge';
import { NodeInputKeyEnum } from '../constants'; import { NodeInputKeyEnum } from '../constants';
import { ClassifyQuestionAgentItemType } from '../template/system/classifyQuestion/type';
import { NextApiResponse } from 'next';
import { UserModelSchema } from '../../../support/user/type';
import { AppDetailType, AppSchema } from '../../app/type';
import { RuntimeNodeItemType } from '../runtime/type';
import { RuntimeEdgeItemType } from './edge';
/* workflow props */
export type ChatDispatchProps = {
res?: NextApiResponse;
mode: 'test' | 'chat' | 'debug';
teamId: string;
tmbId: string;
user: UserModelSchema;
app: AppDetailType | AppSchema;
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
variables: Record<string, any>; // global variable
query: UserChatItemValueItemType[]; // trigger query
stream: boolean;
detail: boolean; // response detail
maxRunTimes: number;
isToolCall?: boolean;
};
export type ModuleDispatchProps<T> = ChatDispatchProps & {
node: RuntimeNodeItemType;
runtimeNodes: RuntimeNodeItemType[];
runtimeEdges: RuntimeEdgeItemType[];
params: T;
};
export type SystemVariablesType = {
appId: string;
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
};
/* node props */
export type RuntimeNodeItemType = { export type RuntimeNodeItemType = {
nodeId: StoreNodeItemType['nodeId']; nodeId: StoreNodeItemType['nodeId'];
name: StoreNodeItemType['name']; name: StoreNodeItemType['name'];
@ -21,6 +66,16 @@ export type RuntimeNodeItemType = {
pluginId?: string; pluginId?: string;
}; };
export type PluginRuntimeType = {
teamId?: string;
name: string;
avatar: string;
showStatus?: boolean;
isTool?: boolean;
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
};
export type RuntimeEdgeItemType = StoreEdgeItemType & { export type RuntimeEdgeItemType = StoreEdgeItemType & {
status: 'waiting' | 'active' | 'skipped'; status: 'waiting' | 'active' | 'skipped';
}; };

View File

@ -1,7 +1,7 @@
import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants'; import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants'; import { NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants';
import { FlowNodeTypeEnum } from '../node/constant'; import { FlowNodeTypeEnum } from '../node/constant';
import { StoreNodeItemType } from '../type'; import { StoreNodeItemType } from '../type/node';
import { StoreEdgeItemType } from '../type/edge'; import { StoreEdgeItemType } from '../type/edge';
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type'; import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
import { VARIABLE_NODE_ID } from '../constants'; import { VARIABLE_NODE_ID } from '../constants';

View File

@ -5,47 +5,51 @@ import { AiChatModule } from './system/aiChat';
import { DatasetSearchModule } from './system/datasetSearch'; import { DatasetSearchModule } from './system/datasetSearch';
import { DatasetConcatModule } from './system/datasetConcat'; import { DatasetConcatModule } from './system/datasetConcat';
import { AssignedAnswerModule } from './system/assignedAnswer'; import { AssignedAnswerModule } from './system/assignedAnswer';
import { ClassifyQuestionModule } from './system/classifyQuestion'; import { ClassifyQuestionModule } from './system/classifyQuestion/index';
import { ContextExtractModule } from './system/contextExtract'; import { ContextExtractModule } from './system/contextExtract/index';
import { HttpModule468 } from './system/http468'; import { HttpNode468 } from './system/http468';
import { ToolModule } from './system/tools'; import { ToolModule } from './system/tools';
import { StopToolNode } from './system/stopTool'; import { StopToolNode } from './system/stopTool';
import { RunAppModule } from './system/runApp'; import { RunAppModule } from './system/runApp/index';
import { PluginInputModule } from './system/pluginInput'; import { PluginInputModule } from './system/pluginInput';
import { PluginOutputModule } from './system/pluginOutput'; import { PluginOutputModule } from './system/pluginOutput';
import { RunPluginModule } from './system/runPlugin'; import { RunPluginModule } from './system/runPlugin';
import { AiQueryExtension } from './system/queryExtension'; import { AiQueryExtension } from './system/queryExtension';
import type { FlowNodeTemplateType } from '../type'; import type { FlowNodeTemplateType } from '../type/node';
import { LafModule } from './system/laf'; import { LafModule } from './system/laf';
import { IfElseNode } from './system/ifElse/index'; import { IfElseNode } from './system/ifElse/index';
import { VariableUpdateNode } from './system/variableUpdate'; import { VariableUpdateNode } from './system/variableUpdate';
import { CodeNode } from './system/sandbox'; import { CodeNode } from './system/sandbox';
import { TextEditorNode } from './system/textEditor';
import { CustomFeedbackNode } from './system/customFeedback';
const systemNodes: FlowNodeTemplateType[] = [ const systemNodes: FlowNodeTemplateType[] = [
AiChatModule, AiChatModule,
TextEditorNode,
AssignedAnswerModule, AssignedAnswerModule,
DatasetSearchModule, DatasetSearchModule,
DatasetConcatModule, DatasetConcatModule,
RunAppModule,
ToolModule, ToolModule,
StopToolNode, StopToolNode,
ClassifyQuestionModule, ClassifyQuestionModule,
ContextExtractModule, ContextExtractModule,
HttpModule468, HttpNode468,
AiQueryExtension, AiQueryExtension,
LafModule, LafModule,
IfElseNode, IfElseNode,
VariableUpdateNode, VariableUpdateNode,
CodeNode CodeNode,
RunAppModule
]; ];
/* app flow module templates */ /* app flow module templates */
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
SystemConfigNode, SystemConfigNode,
WorkflowStart, WorkflowStart,
...systemNodes ...systemNodes,
CustomFeedbackNode
]; ];
/* plugin flow module templates */ /* plugin flow module templates */
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
@ -56,11 +60,11 @@ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
/* all module */ /* all module */
export const moduleTemplatesFlat: FlowNodeTemplateType[] = [ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
...systemNodes, ...appSystemModuleTemplates.concat(
pluginSystemModuleTemplates.filter(
(item) => !appSystemModuleTemplates.find((app) => app.id === item.id)
)
),
EmptyNode, EmptyNode,
SystemConfigNode,
WorkflowStart,
PluginInputModule,
PluginOutputModule,
RunPluginModule RunPluginModule
]; ];

View File

@ -8,10 +8,5 @@ export const Output_Template_AddOutput: FlowNodeOutputItemType = {
key: NodeOutputKeyEnum.addOutputParam, key: NodeOutputKeyEnum.addOutputParam,
type: FlowNodeOutputTypeEnum.dynamic, type: FlowNodeOutputTypeEnum.dynamic,
valueType: WorkflowIOValueTypeEnum.dynamic, valueType: WorkflowIOValueTypeEnum.dynamic,
label: '', label: ''
editField: {
key: true,
valueType: true
}
}; };

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -22,7 +22,7 @@ import { getHandleConfig } from '../utils';
export const AiChatModule: FlowNodeTemplateType = { export const AiChatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.chatNode, id: FlowNodeTypeEnum.chatNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer, templateType: FlowNodeTemplateTypeEnum.ai,
flowNodeType: FlowNodeTypeEnum.chatNode, flowNodeType: FlowNodeTypeEnum.chatNode,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -1,5 +1,5 @@
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -9,7 +9,7 @@ import { getHandleConfig } from '../utils';
export const AssignedAnswerModule: FlowNodeTemplateType = { export const AssignedAnswerModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.answerNode, id: FlowNodeTypeEnum.answerNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer, templateType: FlowNodeTemplateTypeEnum.tools,
flowNodeType: FlowNodeTypeEnum.answerNode, flowNodeType: FlowNodeTypeEnum.answerNode,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -2,26 +2,26 @@ import {
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../../type/node';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
FlowNodeTemplateTypeEnum, FlowNodeTemplateTypeEnum,
NodeOutputKeyEnum NodeOutputKeyEnum
} from '../../constants'; } from '../../../constants';
import { import {
Input_Template_SelectAIModel, Input_Template_SelectAIModel,
Input_Template_History, Input_Template_History,
Input_Template_UserChatInput Input_Template_UserChatInput
} from '../input'; } from '../../input';
import { Input_Template_System_Prompt } from '../input'; import { Input_Template_System_Prompt } from '../../input';
import { LLMModelTypeEnum } from '../../../ai/constants'; import { LLMModelTypeEnum } from '../../../../ai/constants';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../../utils';
export const ClassifyQuestionModule: FlowNodeTemplateType = { export const ClassifyQuestionModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.classifyQuestion, id: FlowNodeTypeEnum.classifyQuestion,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.ai,
flowNodeType: FlowNodeTypeEnum.classifyQuestion, flowNodeType: FlowNodeTypeEnum.classifyQuestion,
sourceHandle: getHandleConfig(false, false, false, false), sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, false, true, true), targetHandle: getHandleConfig(true, false, true, true),

View File

@ -0,0 +1,4 @@
export type ClassifyQuestionAgentItemType = {
value: string;
key: string;
};

View File

@ -2,21 +2,21 @@ import {
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../../type/node';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
NodeOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../../constants';
import { Input_Template_SelectAIModel, Input_Template_History } from '../input'; import { Input_Template_SelectAIModel, Input_Template_History } from '../../input';
import { LLMModelTypeEnum } from '../../../ai/constants'; import { LLMModelTypeEnum } from '../../../../ai/constants';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../../utils';
export const ContextExtractModule: FlowNodeTemplateType = { export const ContextExtractModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.contentExtract, id: FlowNodeTypeEnum.contentExtract,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.ai,
flowNodeType: FlowNodeTypeEnum.contentExtract, flowNodeType: FlowNodeTypeEnum.contentExtract,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -0,0 +1,8 @@
export type ContextExtractAgentItemType = {
valueType: 'string' | 'number' | 'boolean';
desc: string;
key: string;
required: boolean;
defaultValue?: string;
enum?: string;
};

View File

@ -0,0 +1,30 @@
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node.d';
import {
WorkflowIOValueTypeEnum,
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum
} from '../../constants';
import { getHandleConfig } from '../utils';
export const CustomFeedbackNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.customFeedback,
templateType: FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.customFeedback,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/customFeedback.svg',
name: '自定义反馈',
intro: '该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。',
version: '486',
inputs: [
{
key: NodeInputKeyEnum.textareaInput,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
required: true,
label: '反馈的文本'
}
],
outputs: []
};

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -27,8 +27,7 @@ export const getOneQuoteInputTemplate = ({
renderTypeList: [FlowNodeInputTypeEnum.reference], renderTypeList: [FlowNodeInputTypeEnum.reference],
label: `引用${index}`, label: `引用${index}`,
debugLabel: '知识库引用', debugLabel: '知识库引用',
canEdit: key !== defaultQuoteKey, canEdit: true,
description: '',
valueType: WorkflowIOValueTypeEnum.datasetQuote valueType: WorkflowIOValueTypeEnum.datasetQuote
}); });
@ -42,7 +41,7 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
name: '知识库搜索引用合并', name: '知识库搜索引用合并',
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。', intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
showStatus: false, showStatus: false,
version: '481', version: '486',
inputs: [ inputs: [
{ {
key: NodeInputKeyEnum.datasetMaxTokens, key: NodeInputKeyEnum.datasetMaxTokens,
@ -52,11 +51,11 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
valueType: WorkflowIOValueTypeEnum.number valueType: WorkflowIOValueTypeEnum.number
}, },
{ {
key: 'customComponent', key: NodeInputKeyEnum.datasetQuoteList,
renderTypeList: [FlowNodeInputTypeEnum.custom], renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '' label: ''
}, }
getOneQuoteInputTemplate({ key: defaultQuoteKey, index: 1 }) // getOneQuoteInputTemplate({ key: defaultQuoteKey, index: 1 })
], ],
outputs: [ outputs: [
{ {

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -19,7 +19,7 @@ export const Dataset_SEARCH_DESC =
export const DatasetSearchModule: FlowNodeTemplateType = { export const DatasetSearchModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetSearchNode, id: FlowNodeTypeEnum.datasetSearchNode,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.ai,
flowNodeType: FlowNodeTypeEnum.datasetSearchNode, flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -1,5 +1,5 @@
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -14,9 +14,9 @@ import { Input_Template_DynamicInput } from '../input';
import { Output_Template_AddOutput } from '../output'; import { Output_Template_AddOutput } from '../output';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';
export const HttpModule468: FlowNodeTemplateType = { export const HttpNode468: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.httpRequest468, id: FlowNodeTypeEnum.httpRequest468,
templateType: FlowNodeTemplateTypeEnum.externalCall, templateType: FlowNodeTemplateTypeEnum.tools,
flowNodeType: FlowNodeTypeEnum.httpRequest468, flowNodeType: FlowNodeTypeEnum.httpRequest468,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),
@ -30,9 +30,10 @@ export const HttpModule468: FlowNodeTemplateType = {
{ {
...Input_Template_DynamicInput, ...Input_Template_DynamicInput,
description: 'core.module.input.description.HTTP Dynamic Input', description: 'core.module.input.description.HTTP Dynamic Input',
editField: { customInputConfig: {
key: true, selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
valueType: true showDescription: false,
showDefaultValue: true
} }
}, },
{ {
@ -80,7 +81,14 @@ export const HttpModule468: FlowNodeTemplateType = {
} }
], ],
outputs: [ outputs: [
Output_Template_AddOutput, {
...Output_Template_AddOutput,
customFieldConfig: {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
showDescription: false,
showDefaultValue: true
}
},
{ {
id: NodeOutputKeyEnum.error, id: NodeOutputKeyEnum.error,
key: NodeOutputKeyEnum.error, key: NodeOutputKeyEnum.error,

View File

@ -9,7 +9,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../../node/constant'; } from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type'; import { FlowNodeTemplateType } from '../../../type/node';
import { getHandleConfig } from '../../utils'; import { getHandleConfig } from '../../utils';
export const IfElseNode: FlowNodeTemplateType = { export const IfElseNode: FlowNodeTemplateType = {

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -14,9 +14,15 @@ import { Input_Template_DynamicInput } from '../input';
import { Output_Template_AddOutput } from '../output'; import { Output_Template_AddOutput } from '../output';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';
export const nodeLafCustomInputConfig = {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
showDescription: false,
showDefaultValue: true
};
export const LafModule: FlowNodeTemplateType = { export const LafModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.lafModule, id: FlowNodeTypeEnum.lafModule,
templateType: FlowNodeTemplateTypeEnum.externalCall, templateType: FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.lafModule, flowNodeType: FlowNodeTypeEnum.lafModule,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),
@ -30,10 +36,7 @@ export const LafModule: FlowNodeTemplateType = {
{ {
...Input_Template_DynamicInput, ...Input_Template_DynamicInput,
description: '接收前方节点的输出值作为变量,这些变量可以被 Laf 请求参数使用。', description: '接收前方节点的输出值作为变量,这些变量可以被 Laf 请求参数使用。',
editField: { customInputConfig: nodeLafCustomInputConfig
key: true,
valueType: true
}
}, },
{ {
key: NodeInputKeyEnum.httpReqUrl, key: NodeInputKeyEnum.httpReqUrl,

View File

@ -1,6 +1,6 @@
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';
export const PluginInputModule: FlowNodeTemplateType = { export const PluginInputModule: FlowNodeTemplateType = {
@ -12,8 +12,8 @@ export const PluginInputModule: FlowNodeTemplateType = {
unique: true, unique: true,
forbidDelete: true, forbidDelete: true,
avatar: '/imgs/workflow/input.png', avatar: '/imgs/workflow/input.png',
name: '自定义插件输入', name: '插件输入',
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入', intro: '可以配置插件需要哪些输入,利用这些输入来运行插件',
showStatus: false, showStatus: false,
version: '481', version: '481',
inputs: [], inputs: [],

View File

@ -1,6 +1,6 @@
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';
export const PluginOutputModule: FlowNodeTemplateType = { export const PluginOutputModule: FlowNodeTemplateType = {

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,

View File

@ -2,20 +2,20 @@ import {
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
NodeOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../../constants';
import { Input_Template_History, Input_Template_UserChatInput } from '../input'; import { Input_Template_History, Input_Template_UserChatInput } from '../../input';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../../utils';
export const RunAppModule: FlowNodeTemplateType = { export const RunAppModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.runApp, id: FlowNodeTypeEnum.runApp,
templateType: FlowNodeTemplateTypeEnum.externalCall, templateType: FlowNodeTemplateTypeEnum.tools,
flowNodeType: FlowNodeTypeEnum.runApp, flowNodeType: FlowNodeTypeEnum.runApp,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -0,0 +1,5 @@
export type SelectAppItemType = {
id: string;
// name: string;
// logo?: string;
};

View File

@ -1,11 +1,11 @@
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';
export const RunPluginModule: FlowNodeTemplateType = { export const RunPluginModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.pluginModule, id: FlowNodeTypeEnum.pluginModule,
templateType: FlowNodeTemplateTypeEnum.externalCall, templateType: FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.pluginModule, flowNodeType: FlowNodeTypeEnum.pluginModule,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -9,7 +9,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../../node/constant'; } from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type'; import { FlowNodeTemplateType } from '../../../type/node';
import { getHandleConfig } from '../../utils'; import { getHandleConfig } from '../../utils';
import { Input_Template_DynamicInput } from '../../input'; import { Input_Template_DynamicInput } from '../../input';
import { Output_Template_AddOutput } from '../../output'; import { Output_Template_AddOutput } from '../../output';
@ -30,9 +30,10 @@ export const CodeNode: FlowNodeTemplateType = {
{ {
...Input_Template_DynamicInput, ...Input_Template_DynamicInput,
description: '这些变量会作为代码的运行的输入参数', description: '这些变量会作为代码的运行的输入参数',
editField: { customInputConfig: {
key: true, selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
valueType: true showDescription: false,
showDefaultValue: true
} }
}, },
{ {

View File

@ -1,11 +1,11 @@
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/node';
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';
export const StopToolNode: FlowNodeTemplateType = { export const StopToolNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.stopTool, id: FlowNodeTypeEnum.stopTool,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.ai,
flowNodeType: FlowNodeTypeEnum.stopTool, flowNodeType: FlowNodeTypeEnum.stopTool,
sourceHandle: getHandleConfig(false, false, false, false), sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),

View File

@ -1,5 +1,5 @@
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils'; import { getHandleConfig } from '../utils';

View File

@ -0,0 +1,54 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node.d';
import {
WorkflowIOValueTypeEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum
} from '../../constants';
import { getHandleConfig } from '../utils';
import { Input_Template_DynamicInput } from '../input';
export const TextEditorNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.textEditor,
templateType: FlowNodeTemplateTypeEnum.tools,
flowNodeType: FlowNodeTypeEnum.textEditor,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/textEditor.svg',
name: '文本拼接',
intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。',
version: '486',
inputs: [
{
...Input_Template_DynamicInput,
description: '可以引用其他节点的输出,作为文本拼接的变量,通过 {{字段名}} 来引用变量',
customInputConfig: {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
showDescription: false,
showDefaultValue: false
}
},
{
key: NodeInputKeyEnum.textareaInput,
renderTypeList: [FlowNodeInputTypeEnum.textarea],
valueType: WorkflowIOValueTypeEnum.string,
required: true,
label: '拼接文本',
placeholder: '可通过 {{字段名}} 来引用变量'
}
],
outputs: [
{
id: NodeOutputKeyEnum.text,
key: NodeOutputKeyEnum.text,
label: '拼接结果',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.string
}
]
};

View File

@ -3,7 +3,7 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeOutputKeyEnum, NodeOutputKeyEnum,
@ -23,7 +23,7 @@ import { getHandleConfig } from '../utils';
export const ToolModule: FlowNodeTemplateType = { export const ToolModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.tools, id: FlowNodeTypeEnum.tools,
flowNodeType: FlowNodeTypeEnum.tools, flowNodeType: FlowNodeTypeEnum.tools,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.ai,
sourceHandle: getHandleConfig(true, true, false, true), sourceHandle: getHandleConfig(true, true, false, true),
targetHandle: getHandleConfig(true, true, false, true), targetHandle: getHandleConfig(true, true, false, true),
avatar: '/imgs/workflow/tool.svg', avatar: '/imgs/workflow/tool.svg',

View File

@ -1,5 +1,5 @@
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type/index.d'; import { FlowNodeTemplateType } from '../../../type/node.d';
import { import {
FlowNodeTemplateTypeEnum, FlowNodeTemplateTypeEnum,
NodeInputKeyEnum, NodeInputKeyEnum,
@ -25,10 +25,6 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
valueType: WorkflowIOValueTypeEnum.any, valueType: WorkflowIOValueTypeEnum.any,
label: '', label: '',
renderTypeList: [FlowNodeInputTypeEnum.hidden], renderTypeList: [FlowNodeInputTypeEnum.hidden],
editField: {
key: true,
valueType: true
},
value: [ value: [
{ {
variable: ['', ''], variable: ['', ''],

View File

@ -1,5 +1,5 @@
import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d'; import { FlowNodeTemplateType } from '../../type/node.d';
import { import {
WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum,
NodeOutputKeyEnum, NodeOutputKeyEnum,
@ -31,3 +31,6 @@ export const WorkflowStart: FlowNodeTemplateType = {
} }
] ]
}; };
export const isWorkflowStartOutput = (key?: string) =>
!!WorkflowStart.outputs.find((output) => output.key === key);

View File

@ -1,3 +1,5 @@
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './io';
export type FlowNodeChangeProps = { nodeId: string } & ( export type FlowNodeChangeProps = { nodeId: string } & (
| { | {
type: 'attr'; // key: attr, value: new value type: 'attr'; // key: attr, value: new value
@ -7,16 +9,16 @@ export type FlowNodeChangeProps = { nodeId: string } & (
| { | {
type: 'updateInput'; // key: update input key, value: new input value type: 'updateInput'; // key: update input key, value: new input value
key: string; key: string;
value: any; value: FlowNodeInputItemType;
} }
| { | {
type: 'replaceInput'; // key: old input key, value: new input value type: 'replaceInput'; // key: old input key, value: new input value
key: string; key: string;
value: any; value: FlowNodeInputItemType;
} }
| { | {
type: 'addInput'; // key: null, value: new input value type: 'addInput'; // key: null, value: new input value
value: any; value: FlowNodeInputItemType;
index?: number; index?: number;
} }
| { | {
@ -26,16 +28,16 @@ export type FlowNodeChangeProps = { nodeId: string } & (
| { | {
type: 'updateOutput'; // key: update output key, value: new output value type: 'updateOutput'; // key: update output key, value: new output value
key: string; key: string;
value: any; value: FlowNodeOutputItemType;
} }
| { | {
type: 'replaceOutput'; // key: old output key, value: new output value type: 'replaceOutput'; // key: old output key, value: new output value
key: string; key: string;
value: any; value: FlowNodeOutputItemType;
} }
| { | {
type: 'addOutput'; // key: null, value: new output value type: 'addOutput'; // key: null, value: new output value
value: any; value: FlowNodeOutputItemType;
index?: number; index?: number;
} }
| { | {

View File

@ -6,148 +6,53 @@ import {
VariableInputEnum VariableInputEnum
} from '../constants'; } from '../constants';
import { DispatchNodeResponseKeyEnum } from '../runtime/constants'; import { DispatchNodeResponseKeyEnum } from '../runtime/constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './io.d'; import { CustomInputItemType, FlowNodeInputItemType, FlowNodeOutputItemType } from './io.d';
import { UserModelSchema } from '../../../support/user/type';
import { import {
ChatHistoryItemResType, ChatHistoryItemResType,
ChatItemType, ChatItemType,
ChatItemValueItemType, ChatItemValueItemType,
ToolRunResponseItemType, ToolRunResponseItemType
UserChatItemValueItemType
} from '../../chat/type'; } from '../../chat/type';
import { ChatNodeUsageType } from '../../../support/wallet/bill/type'; import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import { RuntimeNodeItemType } from '../runtime/type';
import { PluginTypeEnum } from '../../plugin/constants'; import { PluginTypeEnum } from '../../plugin/constants';
import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge'; import { StoreEdgeItemType } from './edge';
import { NextApiResponse } from 'next'; import { AppChatConfigType } from '../../app/type';
import { AppDetailType, AppSchema } from '../../app/type';
import { ParentIdType } from 'common/parentFolder/type'; import { ParentIdType } from 'common/parentFolder/type';
import { AppTypeEnum } from 'core/app/constants'; import { AppTypeEnum } from 'core/app/constants';
import { FlowNodeTemplateType, StoreNodeItemType } from './node';
export type FlowNodeCommonType = { export type WorkflowTemplateBasicType = {
flowNodeType: FlowNodeTypeEnum; // render node card nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
chatConfigs?: AppChatConfigType;
};
export type WorkflowTemplateType = {
id: string;
parentId?: string;
isFolder?: boolean;
avatar?: string;
name: string; name: string;
intro?: string; // template list intro avatar: string;
showStatus?: boolean; // chatting response step status intro?: string;
author?: string;
version: string; version: string;
// data showStatus?: boolean;
inputs: FlowNodeInputItemType[]; weight?: number;
outputs: FlowNodeOutputItemType[];
// plugin data workflow: WorkflowTemplateBasicType;
pluginId?: string;
pluginType?: AppTypeEnum;
// parentId: ParentIdType;
}; };
// template market
export type FlowNodeTemplateType = FlowNodeCommonType & { export type TemplateMarketItemType = WorkflowTemplateType & {
id: string; // node id, unique tags?: { id: string; label: string }[];
templateType: `${FlowNodeTemplateTypeEnum}`;
// show handle
sourceHandle?: {
left: boolean;
right: boolean;
top: boolean;
bottom: boolean;
};
targetHandle?: {
left: boolean;
right: boolean;
top: boolean;
bottom: boolean;
};
// info
isTool?: boolean; // can be connected by tool
// action
forbidDelete?: boolean; // forbid delete
unique?: boolean;
}; };
export type FlowNodeItemType = FlowNodeTemplateType & { // system plugin
nodeId: string; export type SystemPluginTemplateItemType = WorkflowTemplateType & {
isError?: boolean; templateType: FlowNodeTemplateTypeEnum;
debugResult?: { isTool?: boolean;
status: 'running' | 'success' | 'skipped' | 'failed';
message?: string;
showResult?: boolean; // show and hide result modal
response?: ChatHistoryItemResType;
isExpired?: boolean;
};
};
export type nodeTemplateListType = {
type: `${FlowNodeTemplateTypeEnum}`;
label: string;
list: FlowNodeTemplateType[];
}[];
// store node type originCost: number; // n points/one time
export type StoreNodeItemType = FlowNodeCommonType & { currentCost: number;
nodeId: string;
position?: {
x: number;
y: number;
};
};
/* connection type */ workflow: WorkflowTemplateBasicType;
export type NodeTargetNodeItemType = {
nodeId: string;
sourceHandle: string;
targetHandle: string;
};
export type NodeSourceNodeItemType = {
nodeId: string;
};
/* --------------- function type -------------------- */
export type SelectAppItemType = {
id: string;
// name: string;
// logo?: string;
};
/* agent */
export type ClassifyQuestionAgentItemType = {
value: string;
key: string;
};
export type ContextExtractAgentItemType = {
valueType: 'string' | 'number' | 'boolean';
desc: string;
key: string;
required: boolean;
defaultValue?: string;
enum?: string;
};
/* -------------- running module -------------- */
export type ChatDispatchProps = {
res?: NextApiResponse;
mode: 'test' | 'chat' | 'debug';
teamId: string;
tmbId: string;
user: UserModelSchema;
app: AppDetailType | AppSchema;
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
variables: Record<string, any>; // global variable
query: UserChatItemValueItemType[]; // trigger query
stream: boolean;
detail: boolean; // response detail
maxRunTimes: number;
isToolCall?: boolean;
};
export type ModuleDispatchProps<T> = ChatDispatchProps & {
node: RuntimeNodeItemType;
runtimeNodes: RuntimeNodeItemType[];
runtimeEdges: RuntimeEdgeItemType[];
params: T;
}; };

View File

@ -1,9 +1,43 @@
import { LLMModelTypeEnum } from '../../ai/constants'; import { LLMModelTypeEnum } from '../../ai/constants';
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants'; import { WorkflowIOValueTypeEnum, NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants';
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../node/constant'; import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../node/constant';
import { EditInputFieldMapType, EditNodeFieldType, EditOutputFieldMapType } from '../node/type';
export type FlowNodeInputItemType = { // Dynamic input field configuration
export type CustomFieldConfigType = {
// selectInputTypeList: FlowNodeInputTypeEnum[]; // 可以选哪些输入类型, 只有1个话,则默认选择
// reference
selectValueTypeList?: WorkflowIOValueTypeEnum[]; // 可以选哪个数据类型, 只有1个的话,则默认选择
// showIsToolParam?: boolean; // 是否作为工具参数
// showRequired?: boolean;
// defaultRequired?: boolean;
showDefaultValue?: boolean;
showDescription?: boolean;
};
export type InputComponentPropsType = {
referencePlaceholder?: string;
placeholder?: string; // input,textarea
maxLength?: number; // input,textarea
list?: { label: string; value: string }[]; // select
markList?: { label: string; value: number }[]; // slider
step?: number; // slider
max?: number; // slider, number input
min?: number; // slider, number input
defaultValue?: string;
llmModelType?: `${LLMModelTypeEnum}`;
// dynamic input
customInputConfig?: CustomFieldConfigType;
};
export type FlowNodeInputItemType = InputComponentPropsType & {
selectedTypeIndex?: number; selectedTypeIndex?: number;
renderTypeList: FlowNodeInputTypeEnum[]; // Node Type. Decide on a render style renderTypeList: FlowNodeInputTypeEnum[]; // Node Type. Decide on a render style
@ -16,29 +50,8 @@ export type FlowNodeInputItemType = {
required?: boolean; required?: boolean;
toolDescription?: string; // If this field is not empty, it is entered as a tool toolDescription?: string; // If this field is not empty, it is entered as a tool
maxLength?: number; // input,textarea
// edit
canEdit?: boolean;
// render components params // render components params
referencePlaceholder?: string; canEdit?: boolean; // dynamic inputs
placeholder?: string; // input,textarea
list?: { label: string; value: any }[]; // select
markList?: { label: string; value: any }[]; // slider
step?: number; // slider
max?: number; // slider, number input
min?: number; // slider, number input
defaultValue?: string;
// dynamic input
editField?: EditNodeFieldType['editField'];
dynamicParamDefaultValue?: EditNodeFieldType['dynamicParamDefaultValue'];
llmModelType?: `${LLMModelTypeEnum}`;
}; };
export type FlowNodeOutputItemType = { export type FlowNodeOutputItemType = {
@ -54,8 +67,7 @@ export type FlowNodeOutputItemType = {
required?: boolean; required?: boolean;
// component params // component params
canEdit?: boolean; customFieldConfig?: CustomFieldConfigType;
editField?: EditOutputFieldMapType; // 添加
}; };
export type ReferenceValueProps = [string, string | undefined]; export type ReferenceValueProps = [string, string | undefined];

View File

@ -0,0 +1,111 @@
import { FlowNodeTypeEnum } from '../node/constant';
import {
WorkflowIOValueTypeEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum,
VariableInputEnum
} from '../constants';
import { DispatchNodeResponseKeyEnum } from '../runtime/constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './io.d';
import { UserModelSchema } from '../../../support/user/type';
import {
ChatHistoryItemResType,
ChatItemType,
ChatItemValueItemType,
ToolRunResponseItemType,
UserChatItemValueItemType
} from '../../chat/type';
import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import { RuntimeNodeItemType } from '../runtime/type';
import { PluginTypeEnum } from '../../plugin/constants';
import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge';
import { NextApiResponse } from 'next';
import { AppDetailType, AppSchema } from '../../app/type';
import { ParentIdType } from 'common/parentFolder/type';
import { AppTypeEnum } from 'core/app/constants';
export type FlowNodeCommonType = {
flowNodeType: FlowNodeTypeEnum; // render node card
abandon?: boolean; // abandon node
avatar?: string;
name: string;
intro?: string; // template list intro
showStatus?: boolean; // chatting response step status
version: string;
// data
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
// plugin data
pluginId?: string;
isFolder?: boolean;
// pluginType?: AppTypeEnum;
};
type HandleType = {
left: boolean;
right: boolean;
top: boolean;
bottom: boolean;
};
// system template
export type FlowNodeTemplateType = FlowNodeCommonType & {
id: string; // node id, unique
templateType: FlowNodeTemplateTypeEnum;
// show handle
sourceHandle?: HandleType;
targetHandle?: HandleType;
// info
isTool?: boolean; // can be connected by tool
// action
forbidDelete?: boolean; // forbid delete
unique?: boolean;
};
export type NodeTemplateListItemType = {
id: string; // 系统节点-系统节点的 id 系统插件-插件的 id团队应用的 id
flowNodeType: FlowNodeTypeEnum; // render node card
parentId?: string;
isFolder?: boolean;
templateType: FlowNodeTemplateTypeEnum;
avatar?: string;
name: string;
intro?: string; // template list intro
isTool?: boolean;
author?: string;
unique?: boolean; // 唯一的
};
export type NodeTemplateListType = {
type: FlowNodeTemplateTypeEnum;
label: string;
list: NodeTemplateListItemType[];
}[];
// react flow node type
export type FlowNodeItemType = FlowNodeTemplateType & {
nodeId: string;
isError?: boolean;
debugResult?: {
status: 'running' | 'success' | 'skipped' | 'failed';
message?: string;
showResult?: boolean; // show and hide result modal
response?: ChatHistoryItemResType;
isExpired?: boolean;
};
};
// store node type
export type StoreNodeItemType = FlowNodeCommonType & {
nodeId: string;
// isEntry: boolean;
position?: {
x: number;
y: number;
};
};

View File

@ -6,7 +6,7 @@ import {
variableMap variableMap
} from './constants'; } from './constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './type/io.d'; import { FlowNodeInputItemType, FlowNodeOutputItemType } from './type/io.d';
import { StoreNodeItemType } from './type'; import { StoreNodeItemType } from './type/node';
import type { import type {
VariableItemType, VariableItemType,
AppTTSConfigType, AppTTSConfigType,

View File

@ -37,3 +37,8 @@ export type ResourcePermissionType = {
export type ResourcePerWithTmbWithUser = Omit<ResourcePermissionType, 'tmbId'> & { export type ResourcePerWithTmbWithUser = Omit<ResourcePermissionType, 'tmbId'> & {
tmbId: TeamMemberWithUserSchema; tmbId: TeamMemberWithUserSchema;
}; };
export type PermissionSchemaType = {
defaultPermission: PermissionValueType;
inheritPermission: boolean;
};

View File

@ -1,5 +1,5 @@
import { TeamMemberRoleEnum } from '../user/team/constant'; import { PermissionValueType } from './type';
import { PermissionTypeEnum } from './constant'; import { NullPermission, PermissionTypeEnum } from './constant';
import { Permission } from './controller'; import { Permission } from './controller';
/* team public source, or owner source in team */ /* team public source, or owner source in team */
@ -28,3 +28,17 @@ export function mongoOwnerPermission({ teamId, tmbId }: { teamId: string; tmbId:
tmbId tmbId
}; };
} }
// return permission-related schema to define the schema of resources
export function getPermissionSchema(defaultPermission: PermissionValueType = NullPermission) {
return {
defaultPermission: {
type: Number,
default: defaultPermission
},
inheritPermission: {
type: Boolean,
default: true
}
};
}

View File

@ -1,7 +1,7 @@
import { BillTypeEnum } from './constants'; import { BillTypeEnum } from './constants';
export type CreateBillProps = { export type CreateBillProps = {
type: `${BillTypeEnum}`; type: BillTypeEnum;
// balance // balance
balance?: number; // read balance?: number; // read

View File

@ -9,7 +9,7 @@ export type BillSchemaType = {
createTime: Date; createTime: Date;
orderId: string; orderId: string;
status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED'; status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED';
type: `${BillTypeEnum}`; type: BillTypeEnum;
price: number; price: number;
hasInvoice: boolean; hasInvoice: boolean;
metadata: { metadata: {

View File

@ -21,6 +21,6 @@ export type CreateUsageProps = {
appId?: string; appId?: string;
pluginId?: string; pluginId?: string;
totalPoints: number; totalPoints: number;
source: `${UsageSourceEnum}`; source: UsageSourceEnum;
list: UsageListItemType[]; list: UsageListItemType[];
}; };

View File

@ -0,0 +1,3 @@
# Package 说明
该 package 存放工作流系统插件。

View File

@ -1,10 +1,12 @@
{ {
"name": "@fastgpt/plugins", "name": "@fastgpt/plugins",
"version": "1.0.0", "version": "1.0.0",
"dependencies": {}, "dependencies": {
"expr-eval": "^2.0.2"
},
"devDependencies": { "devDependencies": {
"@types/node": "^20.14.2",
"@fastgpt/global": "workspace:*", "@fastgpt/global": "workspace:*",
"@fastgpt/service": "workspace:*" "@fastgpt/service": "workspace:*",
"@types/node": "^20.14.2"
} }
} }

View File

@ -0,0 +1,57 @@
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { SystemPluginResponseType } from './type';
import { NodeTemplateListItemType } from '@fastgpt/global/core/workflow/type/node';
import { isProduction } from '../service/common/system/constants';
let list = ['getTime', 'fetchUrl', 'mathExprVal'];
export const getCommunityPlugins = () => {
if (isProduction && global.communitySystemPlugins) return global.communitySystemPlugins;
global.communitySystemPlugins = list.map((name) => ({
...require(`./src/${name}/template.json`),
id: `${PluginSourceEnum.community}-${name}`
}));
return global.communitySystemPlugins;
};
export const getCommunityPluginsTemplateList = () => {
return getCommunityPlugins().map<NodeTemplateListItemType>((plugin) => ({
id: plugin.id,
templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.pluginModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,
isTool: plugin.isTool
}));
};
export const getCommunityCb = async () => {
if (isProduction && global.communitySystemPluginCb) return global.communitySystemPluginCb;
// Do not modify the following code
const loadModule = async (name: string) => {
const module = await import(`./src/${name}/index`);
return module.default;
};
const result = await Promise.all(
list.map(async (name) => ({
name,
cb: await loadModule(name)
}))
);
global.communitySystemPluginCb = result.reduce<
Record<string, (e: any) => SystemPluginResponseType>
>((acc, { name, cb }) => {
acc[name] = cb;
return acc;
}, {});
return global.communitySystemPluginCb;
};

View File

@ -0,0 +1,31 @@
import { SystemPluginResponseType } from '../../type';
import { urlsFetch } from '../../../service/common/string/cheerio';
type Props = {
url: string;
};
type Response = Promise<{
result: any;
}>;
const main = async ({ url }: Props): Response => {
try {
const result = await urlsFetch({
urlList: [url],
selector: 'body'
});
const title = result[0]?.title;
const content = result[0]?.content;
return {
result: `${title ? `# ${title}\n\n` : ''}${content}`
};
} catch (error) {
return {
result: 'Fetch error'
};
}
};
export default main;

View File

@ -0,0 +1,265 @@
{
"author": "FastGPT",
"version": "486",
"name": "网页内容抓取",
"avatar": "/imgs/workflow/fetchUrl.svg",
"intro": "可获取一个网页链接内容,并以 Markdown 格式输出,仅支持获取静态网站。",
"showStatus": true,
"weight": 10,
"isTool": true,
"templateType": "tools",
"workflow": {
"nodes": [
{
"nodeId": "lmpb9v2lo2lk",
"name": "自定义插件输入",
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
"avatar": "/imgs/workflow/input.png",
"flowNodeType": "pluginInput",
"showStatus": false,
"position": {
"x": 487.2485939481787,
"y": -159.13661665265613
},
"version": "481",
"inputs": [
{
"renderTypeList": ["reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"key": "url",
"label": "url",
"description": "需要读取的网页链接",
"required": true,
"toolDescription": "需要读取的网页链接"
}
],
"outputs": [
{
"id": "url",
"valueType": "string",
"key": "url",
"label": "url",
"type": "hidden"
}
]
},
{
"nodeId": "i7uow4wj2wdp",
"name": "自定义插件输出",
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
"avatar": "/imgs/workflow/output.png",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 1607.7142331269129,
"y": -150.8808596935447
},
"version": "481",
"inputs": [
{
"key": "result",
"valueType": "string",
"label": "result",
"renderTypeList": ["reference"],
"required": false,
"description": "",
"canEdit": true,
"editField": {
"key": true,
"description": true,
"valueType": true
},
"value": ["ebLCxU43hHuZ", "rH4tMV02robs"]
}
],
"outputs": []
},
{
"nodeId": "ebLCxU43hHuZ",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "/imgs/workflow/http.png",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1050.9890727421412,
"y": -415.2085119990912
},
"version": "486",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "fetchUrl"
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [],
"label": "",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\n \"url\": \"{{url}}\"\n}",
"label": "",
"required": false
},
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "url",
"label": "url",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"required": true,
"value": ["lmpb9v2lo2lk", "url"]
}
],
"outputs": [
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"customFieldConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"id": "error",
"key": "error",
"label": "请求错误",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"label": "原始响应",
"required": true,
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "rH4tMV02robs",
"valueType": "string",
"type": "dynamic",
"key": "result",
"label": "result"
}
]
}
],
"edges": [
{
"source": "lmpb9v2lo2lk",
"target": "ebLCxU43hHuZ",
"sourceHandle": "lmpb9v2lo2lk-source-right",
"targetHandle": "ebLCxU43hHuZ-target-left"
},
{
"source": "ebLCxU43hHuZ",
"target": "i7uow4wj2wdp",
"sourceHandle": "ebLCxU43hHuZ-source-right",
"targetHandle": "i7uow4wj2wdp-target-left"
}
]
}
}

View File

@ -0,0 +1,14 @@
type Props = {
time: string;
};
type Response = Promise<{
time: string;
}>;
const main = async ({ time }: Props): Response => {
return {
time
};
};
export default main;

View File

@ -0,0 +1,215 @@
{
"author": "FastGPT Team",
"version": "481",
"templateType": "tools",
"name": "获取当前时间",
"avatar": "/imgs/workflow/getCurrentTime.svg",
"intro": "获取用户当前时区的时间。",
"showStatus": false,
"isTool": true,
"weight": 10,
"workflow": {
"nodes": [
{
"nodeId": "lmpb9v2lo2lk",
"name": "自定义插件输入",
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
"avatar": "/imgs/workflow/input.png",
"flowNodeType": "pluginInput",
"showStatus": false,
"position": {
"x": 616.4226348688949,
"y": -165.05298493910115
},
"version": "481",
"inputs": [],
"outputs": []
},
{
"nodeId": "i7uow4wj2wdp",
"name": "自定义插件输出",
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
"avatar": "/imgs/workflow/output.png",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 1607.7142331269129,
"y": -150.8808596935447
},
"version": "481",
"inputs": [
{
"key": "time",
"valueType": "string",
"label": "time",
"renderTypeList": ["reference"],
"required": false,
"description": "",
"canEdit": true,
"editField": {
"key": true,
"description": true,
"valueType": true
},
"value": ["ebLCxU43hHuZ", "rH4tMV02robs"]
}
],
"outputs": []
},
{
"nodeId": "ebLCxU43hHuZ",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "/imgs/workflow/http.png",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1050.9890727421412,
"y": -415.2085119990912
},
"version": "481",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "getTime"
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [],
"label": "",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\n \"time\": \"{{cTime}}\"\n}",
"label": "",
"required": false
}
],
"outputs": [
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"customFieldConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"id": "error",
"key": "error",
"label": "请求错误",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"label": "原始响应",
"required": true,
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "rH4tMV02robs",
"valueType": "string",
"type": "dynamic",
"key": "time",
"label": "time"
}
]
}
],
"edges": [
{
"source": "lmpb9v2lo2lk",
"target": "ebLCxU43hHuZ",
"sourceHandle": "lmpb9v2lo2lk-source-right",
"targetHandle": "ebLCxU43hHuZ-target-left"
},
{
"source": "ebLCxU43hHuZ",
"target": "i7uow4wj2wdp",
"sourceHandle": "ebLCxU43hHuZ-source-right",
"targetHandle": "i7uow4wj2wdp-target-left"
}
]
}
}

View File

@ -0,0 +1,40 @@
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { Parser } from 'expr-eval';
type Props = {
expr: string;
};
// Response type same as HTTP outputs
type Response = Promise<{
result: string;
}>;
const replaceSpecialChar = (expr: string) => {
// replace ** to ^
let result = expr.replace(/\*\*/g, '^');
return result;
};
const main = async ({ expr }: Props): Response => {
if (typeof expr !== 'string') {
return {
result: `${expr} is not a string`
};
}
try {
const parser = new Parser();
const exprParser = parser.parse(replaceSpecialChar(expr));
return {
result: exprParser.evaluate()
};
} catch (error) {
return {
result: `${expr} is not a valid math expression. Error: ${error}`
};
}
};
export default main;

View File

@ -0,0 +1,253 @@
{
"author": "FastGPT",
"version": "486",
"name": "数学公式执行",
"avatar": "/imgs/workflow/mathExprEval.svg",
"intro": "用于执行数学表达式的工具,通过 js 的 expr-eval 库运行表达式并返回结果。",
"showStatus": false,
"weight": 10,
"isTool": true,
"templateType": "tools",
"workflow": {
"nodes": [
{
"nodeId": "ioNyiO62aWcG",
"name": "插件输入",
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
"avatar": "/imgs/workflow/input.png",
"flowNodeType": "pluginInput",
"showStatus": false,
"position": {
"x": 494.7780128195933,
"y": -145.65080850146154
},
"version": "481",
"inputs": [
{
"renderTypeList": ["reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"key": "数学表达式",
"label": "数学表达式",
"description": "需要执行的数学表达式",
"required": true,
"toolDescription": "需要执行的数学表达式"
}
],
"outputs": [
{
"id": "数学表达式",
"valueType": "string",
"key": "数学表达式",
"label": "数学表达式",
"type": "hidden"
}
]
},
{
"nodeId": "sowtxkCPjvb7",
"name": "自定义插件输出",
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
"avatar": "/imgs/workflow/output.png",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 1850.4258139184146,
"y": -147.7125146361461
},
"version": "481",
"inputs": [
{
"key": "result",
"valueType": "string",
"label": "result",
"renderTypeList": ["reference"],
"required": false,
"description": "",
"canEdit": true,
"value": ["hzO1JnuLrKpK", "vJnW9JVLOJFT"]
}
],
"outputs": [
{
"id": "sowtxkCPjvb7",
"key": "result",
"valueType": "string",
"label": "result",
"type": "static"
}
]
},
{
"nodeId": "hzO1JnuLrKpK",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "/imgs/workflow/http.png",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1188.947986995841,
"y": -473.52694296182904
},
"version": "481",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "mathExprVal"
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [
{
"key": "Authorization",
"type": "string",
"value": "Bearer fb968ed1-b1dd-4fc1-8409-c9339cbeb14f"
}
],
"label": "",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\n \"expr\":\"{{expr}}\"\n}",
"label": "",
"required": false
},
{
"key": "expr",
"valueType": "string",
"label": "expr",
"renderTypeList": ["reference"],
"canEdit": true,
"value": ["ioNyiO62aWcG", "数学表达式"]
}
],
"outputs": [
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"customFieldConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"id": "error",
"key": "error",
"label": "请求错误",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"label": "原始响应",
"required": true,
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "vJnW9JVLOJFT",
"valueType": "string",
"type": "dynamic",
"key": "result",
"label": "result"
}
]
}
],
"edges": [
{
"source": "ioNyiO62aWcG",
"target": "hzO1JnuLrKpK",
"sourceHandle": "ioNyiO62aWcG-source-right",
"targetHandle": "hzO1JnuLrKpK-target-left"
},
{
"source": "hzO1JnuLrKpK",
"target": "sowtxkCPjvb7",
"sourceHandle": "hzO1JnuLrKpK-source-right",
"targetHandle": "sowtxkCPjvb7-target-left"
}
]
}
}

View File

@ -0,0 +1,21 @@
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
type Props = {
text: string;
};
// Response type same as HTTP outputs
type Response = Promise<{
[NodeInputKeyEnum.answerText]: string;
responseText: string;
}>;
const main = async ({ text }: Props): Response => {
return {
// This output object needs to correspond to the content of the plug-in output
[NodeInputKeyEnum.answerText]: 'AnswerText', // This is a special field, and returning this field will return a message to the client
responseText: `text: ${text}`
};
};
export default main;

View File

@ -0,0 +1,17 @@
{
"author": "",
"version": "486",
"name": "文本加工",
"avatar": "/imgs/workflow/textEditor.svg",
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
"showStatus": false,
"weight": 10,
"isTool": true,
"templateType": "tools",
"workflow": {
"nodes": [],
"edges": []
}
}

7
packages/plugins/type.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
export type SystemPluginResponseType = Promise<Record<string, any>>;
declare global {
var communitySystemPlugins: SystemPluginTemplateItemType[];
var communitySystemPluginCb: Record<string, (e: any) => SystemPluginResponseType>;
}

View File

@ -1,4 +1,4 @@
import { Types, connectionMongo } from '../../mongo'; import { Types, connectionMongo, ReadPreference } from '../../mongo';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants'; import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import fsp from 'fs/promises'; import fsp from 'fs/promises';
import fs from 'fs'; import fs from 'fs';
@ -17,7 +17,9 @@ export function getGFSCollection(bucket: `${BucketNameEnum}`) {
} }
export function getGridBucket(bucket: `${BucketNameEnum}`) { export function getGridBucket(bucket: `${BucketNameEnum}`) {
return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db, { return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db, {
bucketName: bucket bucketName: bucket,
// @ts-ignore
readPreference: ReadPreference.SECONDARY_PREFERRED // Read from secondary node
}); });
} }

View File

@ -10,3 +10,5 @@ export const connectionMongo = (() => {
return global.mongodb; return global.mongodb;
})(); })();
export const ReadPreference = mongoose.mongo.ReadPreference;

View File

@ -43,6 +43,10 @@ export async function connectMongo({
maxIdleTimeMS: 300000, maxIdleTimeMS: 300000,
retryWrites: true, retryWrites: true,
retryReads: true retryReads: true
// readPreference: 'secondaryPreferred',
// readConcern: { level: 'local' },
// writeConcern: { w: 'majority', j: true }
}); });
console.log('mongo connected'); console.log('mongo connected');

View File

@ -1,20 +1,22 @@
import { addLog } from '../system/log'; import { addLog } from '../system/log';
import { connectionMongo, ClientSession } from './index'; import { connectionMongo, ClientSession } from './index';
const timeout = 60000;
export const mongoSessionRun = async <T = unknown>(fn: (session: ClientSession) => Promise<T>) => { export const mongoSessionRun = async <T = unknown>(fn: (session: ClientSession) => Promise<T>) => {
const session = await connectionMongo.startSession(); const session = await connectionMongo.startSession();
let committed = false;
try { try {
session.startTransaction(); session.startTransaction({
maxCommitTimeMS: timeout
});
const result = await fn(session); const result = await fn(session);
await session.commitTransaction(); await session.commitTransaction();
committed = true;
return result as T; return result as T;
} catch (error) { } catch (error) {
if (!committed) { if (!session.transaction.isCommitted) {
await session.abortTransaction(); await session.abortTransaction();
} else { } else {
addLog.warn('Un catch mongo session error', { error }); addLog.warn('Un catch mongo session error', { error });

View File

@ -0,0 +1,4 @@
export const readFromSecondary = {
readPreference: 'secondaryPreferred',
readConcern: 'local'
};

View File

@ -24,6 +24,9 @@ export type InsertVectorControllerProps = InsertVectorProps & {
export type EmbeddingRecallProps = { export type EmbeddingRecallProps = {
teamId: string; teamId: string;
datasetIds: string[]; datasetIds: string[];
forbidCollectionIdList: string[];
// forbidEmbIndexIdList: string[];
// similarity?: number; // similarity?: number;
// efSearch?: number; // efSearch?: number;
}; };

View File

@ -213,14 +213,19 @@ export class MilvusCtrl {
}; };
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => { embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
const client = await this.getClient(); const client = await this.getClient();
const { teamId, datasetIds, vector, limit, retry = 2 } = props; const { teamId, datasetIds, vector, limit, forbidCollectionIdList, retry = 2 } = props;
const forbidColQuery =
forbidCollectionIdList.length > 0
? `and (collectionId not in [${forbidCollectionIdList.map((id) => `"${String(id)}"`).join(',')}])`
: '';
try { try {
const { results } = await client.search({ const { results } = await client.search({
collection_name: DatasetVectorTableName, collection_name: DatasetVectorTableName,
data: vector, data: vector,
limit, limit,
filter: `(teamId == "${teamId}") and (datasetId in [${datasetIds.map((id) => `"${String(id)}"`).join(',')}])`, filter: `(teamId == "${teamId}") and (datasetId in [${datasetIds.map((id) => `"${String(id)}"`).join(',')}]) ${forbidColQuery}`,
output_fields: ['collectionId'] output_fields: ['collectionId']
}); });

View File

@ -118,9 +118,29 @@ export class PgVectorCtrl {
} }
}; };
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => { embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
const { teamId, datasetIds, vector, limit, retry = 2 } = props; const { teamId, datasetIds, vector, limit, forbidCollectionIdList, retry = 2 } = props;
const forbidCollectionSql =
forbidCollectionIdList.length > 0
? `AND collection_id NOT IN (${forbidCollectionIdList.map((id) => `'${String(id)}'`).join(',')})`
: 'AND collection_id IS NOT NULL';
// const forbidDataSql =
// forbidEmbIndexIdList.length > 0 ? `AND id NOT IN (${forbidEmbIndexIdList.join(',')})` : '';
try { try {
// const explan: any = await PgClient.query(
// `BEGIN;
// SET LOCAL hnsw.ef_search = ${global.systemEnv?.pgHNSWEfSearch || 100};
// EXPLAIN ANALYZE select id, collection_id, vector <#> '[${vector}]' AS score
// from ${DatasetVectorTableName}
// where team_id='${teamId}'
// AND dataset_id IN (${datasetIds.map((id) => `'${String(id)}'`).join(',')})
// ${forbidCollectionSql}
// order by score limit ${limit};
// COMMIT;`
// );
// console.log(explan[2].rows);
const results: any = await PgClient.query( const results: any = await PgClient.query(
` `
BEGIN; BEGIN;
@ -129,6 +149,7 @@ export class PgVectorCtrl {
from ${DatasetVectorTableName} from ${DatasetVectorTableName}
where team_id='${teamId}' where team_id='${teamId}'
AND dataset_id IN (${datasetIds.map((id) => `'${String(id)}'`).join(',')}) AND dataset_id IN (${datasetIds.map((id) => `'${String(id)}'`).join(',')})
${forbidCollectionSql}
order by score limit ${limit}; order by score limit ${limit};
COMMIT;` COMMIT;`
); );

View File

@ -1,13 +1,15 @@
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d'; import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant'; import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
import { pluginData2FlowNodeIO } from '@fastgpt/global/core/workflow/utils'; import { pluginData2FlowNodeIO } from '@fastgpt/global/core/workflow/utils';
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants'; import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
import type { PluginRuntimeType, PluginTemplateType } from '@fastgpt/global/core/plugin/type.d'; import type { PluginRuntimeType } from '@fastgpt/global/core/workflow/runtime/type';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants'; import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { getHandleConfig } from '@fastgpt/global/core/workflow/template/utils'; import { getHandleConfig } from '@fastgpt/global/core/workflow/template/utils';
import { getNanoid } from '@fastgpt/global/common/string/tools'; import { getNanoid } from '@fastgpt/global/common/string/tools';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { MongoApp } from '../schema'; import { MongoApp } from '../schema';
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
import { getCommunityPlugins } from '@fastgpt/plugins/register';
/* /*
plugin id rule: plugin id rule:
@ -32,11 +34,15 @@ export async function splitCombinePluginId(id: string) {
return { source, pluginId: id }; return { source, pluginId: id };
} }
const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> => { const getPluginTemplateById = async (
id: string
): Promise<SystemPluginTemplateItemType & { teamId?: string }> => {
const { source, pluginId } = await splitCombinePluginId(id); const { source, pluginId } = await splitCombinePluginId(id);
if (source === PluginSourceEnum.community) { if (source === PluginSourceEnum.community) {
const item = global.communityPlugins?.find((plugin) => plugin.id === pluginId); const item = [...global.communityPlugins, ...getCommunityPlugins()].find(
(plugin) => plugin.id === pluginId
);
if (!item) return Promise.reject('plugin not found'); if (!item) return Promise.reject('plugin not found');
return cloneDeep(item); return cloneDeep(item);
@ -52,12 +58,15 @@ const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> =>
avatar: item.avatar, avatar: item.avatar,
intro: item.intro, intro: item.intro,
showStatus: true, showStatus: true,
source: PluginSourceEnum.personal, workflow: {
nodes: item.modules, nodes: item.modules,
edges: item.edges, edges: item.edges
templateType: FlowNodeTemplateTypeEnum.personalPlugin, },
templateType: FlowNodeTemplateTypeEnum.teamApp,
isTool: true, isTool: true,
version: item?.pluginData?.nodeVersion || defaultNodeVersion version: item?.pluginData?.nodeVersion || defaultNodeVersion,
originCost: 0,
currentCost: 0
}; };
} }
return Promise.reject('plugin not found'); return Promise.reject('plugin not found');
@ -80,7 +89,7 @@ export async function getPluginPreviewNode({ id }: { id: string }): Promise<Flow
version: plugin.version, version: plugin.version,
sourceHandle: getHandleConfig(true, true, true, true), sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true),
...pluginData2FlowNodeIO(plugin.nodes) ...pluginData2FlowNodeIO(plugin.workflow.nodes)
}; };
} }
@ -93,7 +102,7 @@ export async function getPluginRuntimeById(id: string): Promise<PluginRuntimeTyp
name: plugin.name, name: plugin.name,
avatar: plugin.avatar, avatar: plugin.avatar,
showStatus: plugin.showStatus, showStatus: plugin.showStatus,
nodes: plugin.nodes, nodes: plugin.workflow.nodes,
edges: plugin.edges edges: plugin.workflow.edges
}; };
} }

View File

@ -7,6 +7,7 @@ import {
TeamMemberCollectionName TeamMemberCollectionName
} from '@fastgpt/global/support/user/team/constant'; } from '@fastgpt/global/support/user/team/constant';
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant'; import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
import { getPermissionSchema } from '@fastgpt/global/support/permission/utils';
export const AppCollectionName = 'apps'; export const AppCollectionName = 'apps';
@ -108,11 +109,7 @@ const AppSchema = new Schema({
type: Boolean type: Boolean
}, },
// the default permission of a app ...getPermissionSchema(AppDefaultPermissionVal)
defaultPermission: {
type: Number,
default: AppDefaultPermissionVal
}
}); });
try { try {

View File

@ -48,12 +48,15 @@ const DatasetCollectionSchema = new Schema({
type: Date, type: Date,
default: () => new Date() default: () => new Date()
}, },
forbid: {
type: Boolean,
default: false
},
// chunk filed // chunk filed
trainingType: { trainingType: {
type: String, type: String,
enum: Object.keys(TrainingTypeMap), enum: Object.keys(TrainingTypeMap)
required: true
}, },
chunkSize: { chunkSize: {
type: Number, type: Number,
@ -91,23 +94,25 @@ const DatasetCollectionSchema = new Schema({
} }
}); });
export const MongoDatasetCollection: Model<DatasetCollectionSchemaType> =
models[DatasetColCollectionName] || model(DatasetColCollectionName, DatasetCollectionSchema);
try { try {
// auth file // auth file
DatasetCollectionSchema.index({ teamId: 1, fileId: 1 }, { background: true }); DatasetCollectionSchema.index({ teamId: 1, fileId: 1 });
// list collection; deep find collections // list collection; deep find collections
DatasetCollectionSchema.index( DatasetCollectionSchema.index({
{ teamId: 1,
teamId: 1, datasetId: 1,
datasetId: 1, parentId: 1,
parentId: 1, updateTime: -1
updateTime: -1 });
},
{ background: true } // get forbid
); // DatasetCollectionSchema.index({ teamId: 1, datasetId: 1, forbid: 1 });
MongoDatasetCollection.syncIndexes({ background: true });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
export const MongoDatasetCollection: Model<DatasetCollectionSchemaType> =
models[DatasetColCollectionName] || model(DatasetColCollectionName, DatasetCollectionSchema);

View File

@ -53,29 +53,6 @@ export async function findCollectionAndChild({
return [collection, ...childCollections]; return [collection, ...childCollections];
} }
export async function getDatasetCollectionPaths({
parentId = ''
}: {
parentId?: string;
}): Promise<ParentTreePathItemType[]> {
async function find(parentId?: string): Promise<ParentTreePathItemType[]> {
if (!parentId) {
return [];
}
const parent = await MongoDatasetCollection.findOne({ _id: parentId }, 'name parentId');
if (!parent) return [];
const paths = await find(parent.parentId);
paths.push({ parentId, parentName: parent.name });
return paths;
}
return await find(parentId);
}
export function getCollectionUpdateTime({ name, time }: { time?: Date; name: string }) { export function getCollectionUpdateTime({ name, time }: { time?: Date; name: string }) {
if (time) return time; if (time) return time;
if (name.startsWith('手动') || ['manual', 'mark'].includes(name)) return new Date('2999/9/9'); if (name.startsWith('手动') || ['manual', 'mark'].includes(name)) return new Date('2999/9/9');

View File

@ -37,7 +37,7 @@ export async function findDatasetAndAllChildren({
return datasets; return datasets;
}; };
const [dataset, childDatasets] = await Promise.all([ const [dataset, childDatasets] = await Promise.all([
MongoDataset.findById(datasetId), MongoDataset.findById(datasetId).lean(),
find(datasetId) find(datasetId)
]); ]);

View File

@ -77,27 +77,27 @@ const DatasetDataSchema = new Schema({
rebuilding: Boolean rebuilding: Boolean
}); });
try {
// list collection and count data; list data; delete collection(relate data)
DatasetDataSchema.index(
{ teamId: 1, datasetId: 1, collectionId: 1, chunkIndex: 1, updateTime: -1 },
{ background: true }
);
// full text index
DatasetDataSchema.index({ teamId: 1, datasetId: 1, fullTextToken: 'text' }, { background: true });
// Recall vectors after data matching
DatasetDataSchema.index(
{ teamId: 1, datasetId: 1, collectionId: 1, 'indexes.dataId': 1 },
{ background: true }
);
DatasetDataSchema.index({ updateTime: 1 }, { background: true });
// rebuild data
DatasetDataSchema.index({ rebuilding: 1, teamId: 1, datasetId: 1 }, { background: true });
} catch (error) {
console.log(error);
}
export const MongoDatasetData: Model<DatasetDataSchemaType> = export const MongoDatasetData: Model<DatasetDataSchemaType> =
models[DatasetDataCollectionName] || model(DatasetDataCollectionName, DatasetDataSchema); models[DatasetDataCollectionName] || model(DatasetDataCollectionName, DatasetDataSchema);
MongoDatasetData.syncIndexes(); try {
// list collection and count data; list data; delete collection(relate data)
DatasetDataSchema.index({
teamId: 1,
datasetId: 1,
collectionId: 1,
chunkIndex: 1,
updateTime: -1
});
// full text index
DatasetDataSchema.index({ teamId: 1, datasetId: 1, fullTextToken: 'text' });
// Recall vectors after data matching
DatasetDataSchema.index({ teamId: 1, datasetId: 1, collectionId: 1, 'indexes.dataId': 1 });
DatasetDataSchema.index({ updateTime: 1 });
// rebuild data
DatasetDataSchema.index({ rebuilding: 1, teamId: 1, datasetId: 1 });
MongoDatasetData.syncIndexes({ background: true });
} catch (error) {
console.log(error);
}

View File

@ -74,11 +74,6 @@ const DatasetSchema = new Schema({
type: String, type: String,
default: '' default: ''
}, },
permission: {
type: String,
enum: Object.keys(PermissionTypeMap),
default: PermissionTypeEnum.private
},
websiteConfig: { websiteConfig: {
type: { type: {
url: { url: {

View File

@ -12,13 +12,14 @@ import {
DatasetDataWithCollectionType, DatasetDataWithCollectionType,
SearchDataResponseItemType SearchDataResponseItemType
} from '@fastgpt/global/core/dataset/type'; } from '@fastgpt/global/core/dataset/type';
import { MongoDatasetCollection } from '../collection/schema'; import { DatasetColCollectionName, MongoDatasetCollection } from '../collection/schema';
import { reRankRecall } from '../../../core/ai/rerank'; import { reRankRecall } from '../../../core/ai/rerank';
import { countPromptTokens } from '../../../common/string/tiktoken/index'; import { countPromptTokens } from '../../../common/string/tiktoken/index';
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils'; import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
import { hashStr } from '@fastgpt/global/common/string/tools'; import { hashStr } from '@fastgpt/global/common/string/tools';
import { jiebaSplit } from '../../../common/string/jieba'; import { jiebaSplit } from '../../../common/string/jieba';
import { getCollectionSourceData } from '@fastgpt/global/core/dataset/collection/utils'; import { getCollectionSourceData } from '@fastgpt/global/core/dataset/collection/utils';
import { Types } from '../../../common/mongo';
type SearchDatasetDataProps = { type SearchDatasetDataProps = {
teamId: string; teamId: string;
@ -50,9 +51,6 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
usingReRank = usingReRank && global.reRankModels.length > 0; usingReRank = usingReRank && global.reRankModels.length > 0;
// Compatible with topk limit // Compatible with topk limit
if (maxTokens < 50) {
maxTokens = 1500;
}
let set = new Set<string>(); let set = new Set<string>();
let usingSimilarityFilter = false; let usingSimilarityFilter = false;
@ -75,7 +73,29 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
fullTextLimit: 60 fullTextLimit: 60
}; };
}; };
const embeddingRecall = async ({ query, limit }: { query: string; limit: number }) => { const getForbidData = async () => {
const collections = await MongoDatasetCollection.find(
{
teamId,
datasetId: { $in: datasetIds },
forbid: true
},
'_id'
);
return {
forbidCollectionIdList: collections.map((item) => String(item._id))
};
};
const embeddingRecall = async ({
query,
limit,
forbidCollectionIdList
}: {
query: string;
limit: number;
forbidCollectionIdList: string[];
}) => {
const { vectors, tokens } = await getVectorsByText({ const { vectors, tokens } = await getVectorsByText({
model: getVectorModel(model), model: getVectorModel(model),
input: query, input: query,
@ -86,7 +106,8 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
teamId, teamId,
datasetIds, datasetIds,
vector: vectors[0], vector: vectors[0],
limit limit,
forbidCollectionIdList
}); });
// get q and a // get q and a
@ -161,27 +182,66 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
let searchResults = ( let searchResults = (
await Promise.all( await Promise.all(
datasetIds.map((id) => datasetIds.map(async (id) => {
MongoDatasetData.find( return MongoDatasetData.aggregate([
{ {
teamId, $match: {
datasetId: id, teamId: new Types.ObjectId(teamId),
$text: { $search: jiebaSplit({ text: query }) } datasetId: new Types.ObjectId(id),
$text: { $search: jiebaSplit({ text: query }) }
}
}, },
{ {
score: { $meta: 'textScore' }, $addFields: {
_id: 1, score: { $meta: 'textScore' }
datasetId: 1, }
collectionId: 1, },
q: 1, {
a: 1, $sort: {
chunkIndex: 1 score: { $meta: 'textScore' }
}
},
{
$limit: limit
},
{
$lookup: {
from: DatasetColCollectionName,
let: { collectionId: '$collectionId' },
pipeline: [
{
$match: {
$expr: { $eq: ['$_id', '$$collectionId'] },
forbid: { $eq: false } // 直接在lookup阶段过滤
}
},
{
$project: {
_id: 1 // 只需要_id字段来确认匹配
}
}
],
as: 'collection'
}
},
{
$match: {
collection: { $ne: [] }
}
},
{
$project: {
_id: 1,
datasetId: 1,
collectionId: 1,
q: 1,
a: 1,
chunkIndex: 1,
score: 1
}
} }
) ]);
.sort({ score: { $meta: 'textScore' } }) })
.limit(limit)
.lean()
)
) )
).flat() as (DatasetDataSchemaType & { score: number })[]; ).flat() as (DatasetDataSchemaType & { score: number })[];
@ -255,27 +315,6 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
return []; return [];
} }
}; };
const filterResultsByMaxTokens = async (
list: SearchDataResponseItemType[],
maxTokens: number
) => {
const results: SearchDataResponseItemType[] = [];
let totalTokens = 0;
for await (const item of list) {
totalTokens += await countPromptTokens(item.q + item.a);
if (totalTokens > maxTokens + 500) {
break;
}
results.push(item);
if (totalTokens > maxTokens) {
break;
}
}
return results.length === 0 ? list.slice(0, 1) : results;
};
const multiQueryRecall = async ({ const multiQueryRecall = async ({
embeddingLimit, embeddingLimit,
fullTextLimit fullTextLimit
@ -288,12 +327,15 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
const fullTextRecallResList: SearchDataResponseItemType[][] = []; const fullTextRecallResList: SearchDataResponseItemType[][] = [];
let totalTokens = 0; let totalTokens = 0;
const { forbidCollectionIdList } = await getForbidData();
await Promise.all( await Promise.all(
queries.map(async (query) => { queries.map(async (query) => {
const [{ tokens, embeddingRecallResults }, { fullTextRecallResults }] = await Promise.all([ const [{ tokens, embeddingRecallResults }, { fullTextRecallResults }] = await Promise.all([
embeddingRecall({ embeddingRecall({
query, query,
limit: embeddingLimit limit: embeddingLimit,
forbidCollectionIdList
}), }),
fullTextRecall({ fullTextRecall({
query, query,
@ -397,8 +439,28 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
return filterSameDataResults; return filterSameDataResults;
})(); })();
// token filter
const filterMaxTokensResult = await (async () => {
const results: SearchDataResponseItemType[] = [];
let totalTokens = 0;
for await (const item of scoreFilter) {
totalTokens += await countPromptTokens(item.q + item.a);
if (totalTokens > maxTokens + 500) {
break;
}
results.push(item);
if (totalTokens > maxTokens) {
break;
}
}
return results.length === 0 ? scoreFilter.slice(0, 1) : results;
})();
return { return {
searchRes: await filterResultsByMaxTokens(scoreFilter, maxTokens), searchRes: filterMaxTokensResult,
tokens, tokens,
searchMode, searchMode,
limit: maxTokens, limit: maxTokens,

View File

@ -1,6 +1,7 @@
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d'; import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
declare global { declare global {
var communityPluginsV1: PluginTemplateType[]; var communityPluginsV1: PluginTemplateType[];
var communityPlugins: PluginTemplateType[]; var communityPlugins: SystemPluginTemplateItemType[];
} }

View File

@ -3,10 +3,10 @@ import { countMessagesTokens } from '../../../../common/string/tiktoken/index';
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d'; import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants'; import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { getAIApi } from '../../../ai/config'; import { getAIApi } from '../../../ai/config';
import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/workflow/type/index.d'; import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/workflow/template/system/classifyQuestion/type';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d'; import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { replaceVariable } from '@fastgpt/global/common/string/tools'; import { replaceVariable } from '@fastgpt/global/common/string/tools';
import { Prompt_CQJson } from '@fastgpt/global/core/ai/prompt/agent'; import { Prompt_CQJson } from '@fastgpt/global/core/ai/prompt/agent';
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d'; import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';

View File

@ -7,10 +7,10 @@ import {
} from '../../../../common/string/tiktoken/index'; } from '../../../../common/string/tiktoken/index';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants'; import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { getAIApi } from '../../../ai/config'; import { getAIApi } from '../../../ai/config';
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/workflow/type/index.d'; import type { ContextExtractAgentItemType } from '@fastgpt/global/core/workflow/template/system/contextExtract/type';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d'; import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { Prompt_ExtractJson } from '@fastgpt/global/core/ai/prompt/agent'; import { Prompt_ExtractJson } from '@fastgpt/global/core/ai/prompt/agent';
import { replaceVariable, sliceJsonStr } from '@fastgpt/global/common/string/tools'; import { replaceVariable, sliceJsonStr } from '@fastgpt/global/common/string/tools';
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d'; import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';

View File

@ -1,5 +1,5 @@
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d'; import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type'; import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
export type AnswerProps = ModuleDispatchProps<{}>; export type AnswerProps = ModuleDispatchProps<{}>;

View File

@ -377,31 +377,41 @@ async function streamResponse({
if (toolCall.function?.arguments === undefined) { if (toolCall.function?.arguments === undefined) {
toolCall.function.arguments = ''; toolCall.function.arguments = '';
} }
toolCalls.push({
...toolCall,
toolName: toolNode.name,
toolAvatar: toolNode.avatar
});
if (detail) { // Get last tool call
responseWrite({ const lastToolCall = toolCalls[toolCalls.length - 1];
write,
event: SseResponseEventEnum.toolCall, // new tool
data: JSON.stringify({ if (lastToolCall?.id !== toolCall.id) {
tool: { toolCalls.push({
id: toolCall.id, ...toolCall,
toolName: toolNode.name, toolName: toolNode.name,
toolAvatar: toolNode.avatar, toolAvatar: toolNode.avatar
functionName: toolCall.function.name,
params: toolCall.function.arguments,
response: ''
}
})
}); });
}
}
continue; if (detail) {
responseWrite({
write,
event: SseResponseEventEnum.toolCall,
data: JSON.stringify({
tool: {
id: toolCall.id,
toolName: toolNode.name,
toolAvatar: toolNode.avatar,
functionName: toolCall.function.name,
params: toolCall.function.arguments,
response: ''
}
})
});
}
continue;
}
// last tool, update params
} else {
continue;
}
} }
/* arg 插入最后一个工具的参数里 */ /* arg 插入最后一个工具的参数里 */

View File

@ -3,7 +3,7 @@ import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workfl
import type { import type {
ModuleDispatchProps, ModuleDispatchProps,
DispatchNodeResponseType DispatchNodeResponseType
} from '@fastgpt/global/core/workflow/type/index.d'; } from '@fastgpt/global/core/workflow/runtime/type';
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type'; import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type'; import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
import type { DispatchFlowResponse } from '../../type.d'; import type { DispatchFlowResponse } from '../../type.d';

View File

@ -36,7 +36,7 @@ import {
} from '@fastgpt/global/core/ai/prompt/AIChat'; } from '@fastgpt/global/core/ai/prompt/AIChat';
import type { AIChatNodeProps } from '@fastgpt/global/core/workflow/runtime/type.d'; import type { AIChatNodeProps } from '@fastgpt/global/core/workflow/runtime/type.d';
import { replaceVariable } from '@fastgpt/global/common/string/tools'; import { replaceVariable } from '@fastgpt/global/common/string/tools';
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d'; import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { responseWrite, responseWriteController } from '../../../../common/response'; import { responseWrite, responseWriteController } from '../../../../common/response';
import { getLLMModel, ModelTypeEnum } from '../../../ai/model'; import { getLLMModel, ModelTypeEnum } from '../../../ai/model';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type'; import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';

View File

@ -1,4 +1,4 @@
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d'; import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type'; import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
import axios from 'axios'; import axios from 'axios';
@ -8,7 +8,7 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
type RunCodeType = ModuleDispatchProps<{ type RunCodeType = ModuleDispatchProps<{
[NodeInputKeyEnum.codeType]: 'js'; [NodeInputKeyEnum.codeType]: 'js';
[NodeInputKeyEnum.code]: string; [NodeInputKeyEnum.code]: string;
[key: string]: any; [NodeInputKeyEnum.addInputParam]: Record<string, any>;
}>; }>;
type RunCodeResponse = DispatchNodeResultType<{ type RunCodeResponse = DispatchNodeResultType<{
[NodeOutputKeyEnum.error]?: any; [NodeOutputKeyEnum.error]?: any;
@ -18,7 +18,7 @@ type RunCodeResponse = DispatchNodeResultType<{
export const dispatchRunCode = async (props: RunCodeType): Promise<RunCodeResponse> => { export const dispatchRunCode = async (props: RunCodeType): Promise<RunCodeResponse> => {
const { const {
params: { codeType, code, ...customVariables } params: { codeType, code, [NodeInputKeyEnum.addInputParam]: customVariables }
} = props; } = props;
const sandBoxRequestUrl = `${process.env.SANDBOX_URL}/sandbox/js`; const sandBoxRequestUrl = `${process.env.SANDBOX_URL}/sandbox/js`;

View File

@ -1,5 +1,5 @@
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type'; import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d'; import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils'; import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
import { filterSearchResultsByMaxChars } from '../../utils'; import { filterSearchResultsByMaxChars } from '../../utils';

Some files were not shown because too many files have changed in this diff Show More