fix: create plugin by curl (#3580)

This commit is contained in:
Archer
2025-01-13 18:27:31 +08:00
committed by GitHub
parent e933dacb05
commit 80c8897e10
6 changed files with 178 additions and 118 deletions

View File

@@ -159,6 +159,14 @@ services:
# 日志等级: debug, info, warn, error
- LOG_LEVEL=info
- STORE_LOG_LEVEL=warn
# 工作流最大运行次数
- WORKFLOW_MAX_RUN_TIMES=1000
# 批量执行节点,最大输入长度
- WORKFLOW_MAX_LOOP_TIMES=100
# 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割)
- ALLOWED_ORIGINS=
# 是否开启IP限制默认不开启
- USE_IP_LIMIT=false
volumes:
- ./config.json:/app/data/config.json

View File

@@ -116,6 +116,14 @@ services:
# 日志等级: debug, info, warn, error
- LOG_LEVEL=info
- STORE_LOG_LEVEL=warn
# 工作流最大运行次数
- WORKFLOW_MAX_RUN_TIMES=1000
# 批量执行节点,最大输入长度
- WORKFLOW_MAX_LOOP_TIMES=100
# 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割)
- ALLOWED_ORIGINS=
# 是否开启IP限制默认不开启
- USE_IP_LIMIT=false
volumes:
- ./config.json:/app/data/config.json

View File

@@ -97,6 +97,14 @@ services:
# 日志等级: debug, info, warn, error
- LOG_LEVEL=info
- STORE_LOG_LEVEL=warn
# 工作流最大运行次数
- WORKFLOW_MAX_RUN_TIMES=1000
# 批量执行节点,最大输入长度
- WORKFLOW_MAX_LOOP_TIMES=100
# 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割)
- ALLOWED_ORIGINS=
# 是否开启IP限制默认不开启
- USE_IP_LIMIT=false
volumes:
- ./config.json:/app/data/config.json

View File

@@ -49,9 +49,10 @@ export type FlowNodeInputItemType = InputComponentPropsType & {
debugLabel?: string;
description?: string; // field desc
required?: boolean;
toolDescription?: string; // If this field is not empty, it is entered as a tool
enum?: string;
toolDescription?: string; // If this field is not empty, it is entered as a tool
// render components params
canEdit?: boolean; // dynamic inputs
isPro?: boolean; // Pro version field

View File

@@ -210,7 +210,7 @@ export const runToolWithToolChoice = async (
properties[item.key] = {
...jsonSchema,
description: item.toolDescription || '',
enum: item.enum?.split('\n').filter(Boolean) || []
enum: item.enum?.split('\n').filter(Boolean) || undefined
};
});
@@ -227,6 +227,7 @@ export const runToolWithToolChoice = async (
}
};
});
// Filter histories by maxToken
const filterMessages = (
await filterGPTMessageByMaxTokens({

View File

@@ -1,20 +1,16 @@
// @ts-nocheck
import { AppItemType } from '@/types/app';
import { parseCurl } from '@fastgpt/global/common/string/http';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { AppSchema } from '@fastgpt/global/core/app/type';
import {
NodeOutputKeyEnum,
WorkflowIOValueTypeEnum
} from '@fastgpt/global/core/workflow/constants';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '@fastgpt/global/core/workflow/node/constant';
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import {
FlowNodeInputItemType,
FlowNodeOutputItemType
} from '@fastgpt/global/core/workflow/type/io';
import { i18nT } from '@fastgpt/web/i18n/utils';
export const emptyTemplates: Record<
@@ -254,7 +250,8 @@ export const emptyTemplates: Record<
sourceHandle: '448745-source-right',
targetHandle: 'loOvhld2ZTKa-target-left'
}
]
],
chatConfig: {}
},
[AppTypeEnum.workflow]: {
avatar: 'core/app/type/workflowFill',
@@ -265,7 +262,7 @@ export const emptyTemplates: Record<
name: i18nT('common:core.module.template.system_config'),
intro: i18nT('common:core.module.template.system_config_info'),
avatar: 'core/workflow/template/systemConfig',
flowNodeType: 'userGuide',
flowNodeType: FlowNodeTypeEnum.systemConfig,
position: {
x: 262.2732338817093,
y: -476.00241136598146
@@ -274,22 +271,22 @@ export const emptyTemplates: Record<
inputs: [
{
key: 'welcomeText',
renderTypeList: ['hidden'],
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
label: 'core.app.Welcome Text',
value: ''
},
{
key: 'variables',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
label: 'core.app.Chat Variable',
value: []
},
{
key: 'questionGuide',
valueType: 'any',
renderTypeList: ['hidden'],
valueType: WorkflowIOValueTypeEnum.any,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: 'core.app.Question Guide',
value: {
open: false
@@ -297,8 +294,8 @@ export const emptyTemplates: Record<
},
{
key: 'tts',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
value: {
type: 'web'
@@ -306,8 +303,8 @@ export const emptyTemplates: Record<
},
{
key: 'whisper',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
value: {
open: false,
@@ -317,8 +314,8 @@ export const emptyTemplates: Record<
},
{
key: 'scheduleTrigger',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
value: null
}
@@ -330,7 +327,7 @@ export const emptyTemplates: Record<
name: i18nT('common:core.module.template.work_start'),
intro: '',
avatar: 'core/workflow/template/workflowStart',
flowNodeType: 'workflowStart',
flowNodeType: FlowNodeTypeEnum.workflowStart,
position: {
x: 632.368838596004,
y: -347.7446492944009
@@ -339,8 +336,8 @@ export const emptyTemplates: Record<
inputs: [
{
key: 'userChatInput',
renderTypeList: ['reference', 'textarea'],
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea],
valueType: WorkflowIOValueTypeEnum.string,
label: i18nT('common:core.module.input.label.user question'),
required: true,
toolDescription: i18nT('common:core.module.input.label.user question')
@@ -351,13 +348,14 @@ export const emptyTemplates: Record<
id: 'userChatInput',
key: 'userChatInput',
label: 'common:core.module.input.label.user question',
type: 'static',
valueType: 'string'
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.string
}
]
}
],
edges: []
edges: [],
chatConfig: {}
},
[AppTypeEnum.plugin]: {
avatar: 'core/app/type/pluginFill',
@@ -406,7 +404,8 @@ export const emptyTemplates: Record<
outputs: []
}
],
edges: []
edges: [],
chatConfig: {}
}
};
@@ -420,34 +419,66 @@ export const parsePluginFromCurlString = (
const { url, method, headers, body, params, bodyArray } = parseCurl(curl);
const allInputs = Array.from(
new Map([...headers, ...params, ...bodyArray].map((item) => [item.key, item])).values()
new Map([...params, ...bodyArray].map((item) => [item.key, item])).values()
);
const formatInputs = allInputs.map((item) => {
const valueType = item.value === null ? 'string' : typeof item.value;
return {
renderTypeList: ['reference'],
selectedTypeIndex: 0,
valueType,
canEdit: true,
key: item.key,
label: item.key,
description: item.key,
defaultValue: '',
required: false,
toolDescription: ['string', 'number', 'boolean'].includes(valueType) ? item.key : ''
};
});
const formatOutputs = formatInputs.map((item) => ({
const formatPluginStartInputs = allInputs
.map((item) => {
const valueType = item.value === null ? 'string' : typeof item.value;
const valueTypeMap = {
string: {
renderTypeList: [FlowNodeInputTypeEnum.input, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
isToolType: true,
defaultValue: item.value
},
number: {
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.number,
isToolType: true,
defaultValue: item.value
},
boolean: {
renderTypeList: [FlowNodeInputTypeEnum.switch, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.boolean,
isToolType: true,
defaultValue: item.value
},
object: {
renderTypeList: [FlowNodeInputTypeEnum.JSONEditor, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.object,
isToolType: false,
defaultValue: ''
}
};
const valueTypeItem = valueTypeMap[valueType as keyof typeof valueTypeMap];
if (!valueTypeItem) return;
return {
renderTypeList: valueTypeItem.renderTypeList,
selectedTypeIndex: 0,
valueType: valueTypeItem.valueType,
canEdit: true,
key: item.key,
label: item.key,
description: '',
defaultValue: valueTypeItem.defaultValue,
required: false,
toolDescription: valueTypeItem.isToolType ? item.key : ''
};
})
.filter(Boolean) as FlowNodeInputItemType[];
const formatPluginStartOutputs = formatPluginStartInputs.map<FlowNodeOutputItemType>((item) => ({
id: item.key,
key: item.key,
label: item.key,
valueType: item.valueType,
type: 'hidden'
type: FlowNodeOutputTypeEnum.hidden
}));
const referenceHeaders = headers.map((item) => ({
key: item.key,
value: `{{$pluginInput.${item.key}$}}`,
value: item.value,
type: item.type
}));
const referenceParams = params.map((item) => ({
@@ -457,14 +488,17 @@ export const parsePluginFromCurlString = (
}));
const referenceBody = Object.entries(JSON.parse(body)).reduce(
(acc, [key, value]) => {
acc[key] = `{{$pluginInput.${key}$}}`;
acc[key] =
typeof value === 'string' ? `###{{$pluginInput.${key}$}}###` : `{{$pluginInput.${key}$}}`;
return acc;
},
{} as Record<string, any>
);
const referenceBodyStr = JSON.stringify(referenceBody, null, 2)
.replace(/"{{\$/g, '{{$')
.replace(/\$}}"/g, '$}}');
.replace(/\$}}"/g, '$}}')
.replace(/###{{\$/g, '{{$')
.replace(/\$}}###/g, '$}}');
return {
nodes: [
@@ -473,22 +507,22 @@ export const parsePluginFromCurlString = (
name: i18nT('workflow:template.plugin_start'),
intro: i18nT('workflow:intro_plugin_input'),
avatar: 'core/workflow/template/workflowStart',
flowNodeType: 'pluginInput',
flowNodeType: FlowNodeTypeEnum.pluginInput,
showStatus: false,
position: {
x: 427.6554681270263,
y: -291.6987155252725
},
version: '481',
inputs: formatInputs,
outputs: formatOutputs
inputs: formatPluginStartInputs,
outputs: formatPluginStartOutputs
},
{
nodeId: 'pluginOutput',
name: i18nT('common:core.module.template.self_output'),
intro: i18nT('workflow:intro_custom_plugin_output'),
avatar: 'core/workflow/template/pluginOutput',
flowNodeType: 'pluginOutput',
flowNodeType: FlowNodeTypeEnum.pluginOutput,
showStatus: false,
position: {
x: 1870.1072210870427,
@@ -497,8 +531,8 @@ export const parsePluginFromCurlString = (
version: '481',
inputs: [
{
renderTypeList: ['reference'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.any,
canEdit: true,
key: 'result',
label: 'result',
@@ -508,8 +542,8 @@ export const parsePluginFromCurlString = (
value: ['vumlECDQTjeC', 'httpRawResponse']
},
{
renderTypeList: ['reference'],
valueType: 'object',
renderTypeList: [FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.object,
canEdit: true,
key: 'error',
label: 'error',
@@ -526,7 +560,7 @@ export const parsePluginFromCurlString = (
name: 'HTTP 请求',
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
avatar: 'core/workflow/template/httpRequest',
flowNodeType: 'httpRequest468',
flowNodeType: FlowNodeTypeEnum.httpRequest468,
showStatus: true,
position: {
x: 1049.4419012643668,
@@ -536,28 +570,28 @@ export const parsePluginFromCurlString = (
inputs: [
{
key: 'system_addInputParam',
renderTypeList: ['addInputParam'],
valueType: 'dynamic',
renderTypeList: [FlowNodeInputTypeEnum.addInputParam],
valueType: WorkflowIOValueTypeEnum.dynamic,
label: '',
required: false,
description: '接收前方节点的输出值作为变量,这些变量可以被 HTTP 请求参数使用。',
customInputConfig: {
selectValueTypeList: [
'string',
'number',
'boolean',
'object',
'arrayString',
'arrayNumber',
'arrayBoolean',
'arrayObject',
'arrayAny',
'any',
'chatHistory',
'datasetQuote',
'dynamic',
'selectApp',
'selectDataset'
WorkflowIOValueTypeEnum.string,
WorkflowIOValueTypeEnum.number,
WorkflowIOValueTypeEnum.boolean,
WorkflowIOValueTypeEnum.object,
WorkflowIOValueTypeEnum.arrayString,
WorkflowIOValueTypeEnum.arrayNumber,
WorkflowIOValueTypeEnum.arrayBoolean,
WorkflowIOValueTypeEnum.arrayObject,
WorkflowIOValueTypeEnum.arrayAny,
WorkflowIOValueTypeEnum.any,
WorkflowIOValueTypeEnum.chatHistory,
WorkflowIOValueTypeEnum.datasetQuote,
WorkflowIOValueTypeEnum.dynamic,
WorkflowIOValueTypeEnum.selectApp,
WorkflowIOValueTypeEnum.selectDataset
],
showDescription: false,
showDefaultValue: true
@@ -568,8 +602,8 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpMethod',
renderTypeList: ['custom'],
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
value: method,
required: true,
@@ -580,8 +614,8 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpTimeout',
renderTypeList: ['custom'],
valueType: 'number',
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.number,
label: '',
value: 30,
min: 5,
@@ -594,8 +628,8 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpReqUrl',
renderTypeList: ['hidden'],
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
description:
'新的 HTTP 请求地址。如果出现两个"请求地址",可以删除该模块重新加入,会拉取最新的模块配置。',
@@ -608,8 +642,8 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpHeader',
renderTypeList: ['custom'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.any,
value: referenceHeaders,
label: '',
description:
@@ -622,22 +656,21 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpParams',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: referenceParams,
description:
'新的 HTTP 请求地址。如果出现两个“请求地址”,可以删除该模块重新加入,会拉取最新的模块配置。',
label: '',
required: false,
valueDesc: '',
description: '',
debugLabel: '',
toolDescription: ''
},
{
key: 'system_httpJsonBody',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: referenceBodyStr,
label: '',
required: false,
@@ -648,8 +681,8 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpFormBody',
renderTypeList: ['hidden'],
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: [],
label: '',
required: false,
@@ -660,8 +693,8 @@ export const parsePluginFromCurlString = (
},
{
key: 'system_httpContentType',
renderTypeList: ['hidden'],
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
value: 'json',
label: '',
required: false,
@@ -675,26 +708,26 @@ export const parsePluginFromCurlString = (
{
id: 'system_addOutputParam',
key: 'system_addOutputParam',
type: 'dynamic',
valueType: 'dynamic',
type: FlowNodeOutputTypeEnum.dynamic,
valueType: WorkflowIOValueTypeEnum.dynamic,
label: '输出字段提取',
customFieldConfig: {
selectValueTypeList: [
'string',
'number',
'boolean',
'object',
'arrayString',
'arrayNumber',
'arrayBoolean',
'arrayObject',
'arrayAny',
'any',
'chatHistory',
'datasetQuote',
'dynamic',
'selectApp',
'selectDataset'
WorkflowIOValueTypeEnum.string,
WorkflowIOValueTypeEnum.number,
WorkflowIOValueTypeEnum.boolean,
WorkflowIOValueTypeEnum.object,
WorkflowIOValueTypeEnum.arrayString,
WorkflowIOValueTypeEnum.arrayNumber,
WorkflowIOValueTypeEnum.arrayBoolean,
WorkflowIOValueTypeEnum.arrayObject,
WorkflowIOValueTypeEnum.arrayAny,
WorkflowIOValueTypeEnum.any,
WorkflowIOValueTypeEnum.chatHistory,
WorkflowIOValueTypeEnum.datasetQuote,
WorkflowIOValueTypeEnum.dynamic,
WorkflowIOValueTypeEnum.selectApp,
WorkflowIOValueTypeEnum.selectDataset
],
showDescription: false,
showDefaultValue: false
@@ -707,8 +740,8 @@ export const parsePluginFromCurlString = (
key: 'error',
label: '请求错误',
description: 'HTTP请求错误信息成功时返回空',
valueType: 'object',
type: 'static',
valueType: WorkflowIOValueTypeEnum.object,
type: FlowNodeOutputTypeEnum.static,
valueDesc: ''
},
{
@@ -717,8 +750,8 @@ export const parsePluginFromCurlString = (
required: true,
label: '原始响应',
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
valueType: 'any',
type: 'static',
valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.static,
valueDesc: ''
}
]
@@ -751,6 +784,7 @@ export const parsePluginFromCurlString = (
sourceHandle: 'vumlECDQTjeC-source-right',
targetHandle: 'pluginOutput-target-left'
}
]
],
chatConfig: {}
};
};