feat: adapt v1 system plugin (#1366)
This commit is contained in:
parent
8863337606
commit
db1c27cdc7
1
packages/service/core/plugin/type.d.ts
vendored
1
packages/service/core/plugin/type.d.ts
vendored
@ -1,5 +1,6 @@
|
|||||||
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
var communityPluginsV1: PluginTemplateType[];
|
||||||
var communityPlugins: PluginTemplateType[];
|
var communityPlugins: PluginTemplateType[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -279,7 +279,7 @@ export async function dispatchWorkFlowV1({
|
|||||||
)?.targets?.length;
|
)?.targets?.length;
|
||||||
|
|
||||||
return moduleOutput(module, {
|
return moduleOutput(module, {
|
||||||
[NodeOutputKeyEnum.finish]: true,
|
finish: true,
|
||||||
[NodeOutputKeyEnum.userChatInput]: hasUserChatInputTarget
|
[NodeOutputKeyEnum.userChatInput]: hasUserChatInputTarget
|
||||||
? params[NodeOutputKeyEnum.userChatInput]
|
? params[NodeOutputKeyEnum.userChatInput]
|
||||||
: undefined,
|
: undefined,
|
||||||
@ -295,7 +295,7 @@ export async function dispatchWorkFlowV1({
|
|||||||
modules.forEach((item) => {
|
modules.forEach((item) => {
|
||||||
item.isEntry = false;
|
item.isEntry = false;
|
||||||
});
|
});
|
||||||
|
// console.log(JSON.stringify(runningModules, null, 2));
|
||||||
initModules.map((module) =>
|
initModules.map((module) =>
|
||||||
moduleInput(module, {
|
moduleInput(module, {
|
||||||
...startParams,
|
...startParams,
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||||
import { dispatchWorkFlowV1 } from '../index';
|
import { dispatchWorkFlowV1 } from '../index';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import {
|
||||||
|
FlowNodeTemplateTypeEnum,
|
||||||
|
NodeInputKeyEnum
|
||||||
|
} 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 { getPluginRuntimeById } from '../../../plugin/controller';
|
import { splitCombinePluginId } from '../../../plugin/controller';
|
||||||
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
||||||
import { setEntryEntries, DYNAMIC_INPUT_KEY } from '../utils';
|
import { setEntryEntries, DYNAMIC_INPUT_KEY } from '../utils';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
import { PluginRuntimeType, PluginTemplateType } from '@fastgpt/global/core/plugin/type';
|
||||||
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
import { MongoPlugin } from '../../../plugin/schema';
|
||||||
|
|
||||||
type RunPluginProps = ModuleDispatchProps<{
|
type RunPluginProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.pluginId]: string;
|
[NodeInputKeyEnum.pluginId]: string;
|
||||||
@ -15,6 +22,45 @@ type RunPluginProps = ModuleDispatchProps<{
|
|||||||
}>;
|
}>;
|
||||||
type RunPluginResponse = DispatchNodeResultType<{}>;
|
type RunPluginResponse = DispatchNodeResultType<{}>;
|
||||||
|
|
||||||
|
const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> => {
|
||||||
|
const { source, pluginId } = await splitCombinePluginId(id);
|
||||||
|
if (source === PluginSourceEnum.community) {
|
||||||
|
const item = global.communityPluginsV1?.find((plugin) => plugin.id === pluginId);
|
||||||
|
|
||||||
|
if (!item) return Promise.reject('plugin not found');
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (source === PluginSourceEnum.personal) {
|
||||||
|
const item = await MongoPlugin.findById(id).lean();
|
||||||
|
if (!item) return Promise.reject('plugin not found');
|
||||||
|
return {
|
||||||
|
id: String(item._id),
|
||||||
|
teamId: String(item.teamId),
|
||||||
|
name: item.name,
|
||||||
|
avatar: item.avatar,
|
||||||
|
intro: item.intro,
|
||||||
|
showStatus: true,
|
||||||
|
source: PluginSourceEnum.personal,
|
||||||
|
modules: item.modules,
|
||||||
|
templateType: FlowNodeTemplateTypeEnum.personalPlugin
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Promise.reject('plugin not found');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPluginRuntimeById = async (id: string): Promise<PluginRuntimeType> => {
|
||||||
|
const plugin = await getPluginTemplateById(id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
teamId: plugin.teamId,
|
||||||
|
name: plugin.name,
|
||||||
|
avatar: plugin.avatar,
|
||||||
|
showStatus: plugin.showStatus,
|
||||||
|
modules: plugin.modules
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPluginResponse> => {
|
export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPluginResponse> => {
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
@ -31,7 +77,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
const plugin = await getPluginRuntimeById(pluginId);
|
const plugin = await getPluginRuntimeById(pluginId);
|
||||||
|
|
||||||
// concat dynamic inputs
|
// concat dynamic inputs
|
||||||
const inputModule = plugin.nodes.find((item) => item.flowType === FlowNodeTypeEnum.pluginInput);
|
const inputModule = plugin.modules.find((item) => item.flowType === FlowNodeTypeEnum.pluginInput);
|
||||||
if (!inputModule) return Promise.reject('Plugin error, It has no set input.');
|
if (!inputModule) return Promise.reject('Plugin error, It has no set input.');
|
||||||
const hasDynamicInput = inputModule.inputs.find((input) => input.key === DYNAMIC_INPUT_KEY);
|
const hasDynamicInput = inputModule.inputs.find((input) => input.key === DYNAMIC_INPUT_KEY);
|
||||||
|
|
||||||
@ -56,7 +102,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
|
|
||||||
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlowV1({
|
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlowV1({
|
||||||
...props,
|
...props,
|
||||||
modules: setEntryEntries(plugin.nodes).map((module) => ({
|
modules: setEntryEntries(plugin.modules).map((module) => ({
|
||||||
...module,
|
...module,
|
||||||
showStatus: false
|
showStatus: false
|
||||||
})),
|
})),
|
||||||
|
|||||||
@ -32,6 +32,6 @@ export const dispatchAnswer = (props: Record<string, any>): AnswerResponse => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[NodeOutputKeyEnum.answerText]: formatText
|
[NodeOutputKeyEnum.answerText]: `\n${formatText}`
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -142,7 +142,7 @@
|
|||||||
"description": "core.module.input.description.Http Request Url",
|
"description": "core.module.input.description.Http Request Url",
|
||||||
"placeholder": "https://api.ai.com/getInventory",
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
"required": false,
|
"required": false,
|
||||||
"value": "/api/plugins/customFeedback"
|
"value": "/api/plugins/customFeedback/v2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "system_httpHeader",
|
"key": "system_httpHeader",
|
||||||
|
|||||||
@ -167,7 +167,7 @@
|
|||||||
"description": "core.module.input.description.Http Request Url",
|
"description": "core.module.input.description.Http Request Url",
|
||||||
"placeholder": "https://api.ai.com/getInventory",
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
"required": false,
|
"required": false,
|
||||||
"value": "/api/plugins/textEditor"
|
"value": "/api/plugins/textEditor/v2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "system_httpHeader",
|
"key": "system_httpHeader",
|
||||||
|
|||||||
342
projects/app/data/pluginTemplates/v1/customFeedback.json
Normal file
342
projects/app/data/pluginTemplates/v1/customFeedback.json
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
{
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "other",
|
||||||
|
"name": "自定义反馈",
|
||||||
|
"avatar": "/imgs/module/customFeedback.svg",
|
||||||
|
"intro": "该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": false,
|
||||||
|
"weight": 0,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "w90mfp",
|
||||||
|
"name": "定义插件输入",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 515.1887815471657,
|
||||||
|
"y": -169.04905809653783
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "defaultFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "默认反馈内容",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": false,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "自定义反馈内容",
|
||||||
|
"type": "target",
|
||||||
|
"required": false,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "defaultFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "默认反馈内容",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "defaultFeedback"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "自定义反馈内容",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "customFeedback"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"name": "HTTP模块",
|
||||||
|
"flowType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1086.8929621216014,
|
||||||
|
"y": -451.7550009773506
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"label": "GET",
|
||||||
|
"value": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "POST",
|
||||||
|
"value": "POST"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"value": "/api/plugins/customFeedback",
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"appId\": \"{{appId}}\",\r\n \"chatId\": \"{{chatId}}\",\r\n \"responseChatItemId\": \"{{responseChatItemId}}\",\r\n \"defaultFeedback\": \"{{defaultFeedback}}\",\r\n \"customFeedback\": \"{{customFeedback}}\"\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.inputType.dynamicTargetInput",
|
||||||
|
"description": "core.module.input.description.dynamic input",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"hideInApp": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "defaultFeedback",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true,
|
||||||
|
"key": "defaultFeedback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "customFeedback",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "addOutputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"targets": [],
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"outputType": "source",
|
||||||
|
"valueType": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "response",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "s15f3v",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"key": "response"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "s15f3v",
|
||||||
|
"name": "指定回复",
|
||||||
|
"flowType": "answerNode",
|
||||||
|
"position": {
|
||||||
|
"x": 1705.6337348182756,
|
||||||
|
"y": -37.53826066726282
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"type": "textarea",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.input.label.Response content",
|
||||||
|
"description": "core.module.input.description.Response content",
|
||||||
|
"placeholder": "core.module.input.description.Response content",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
195
projects/app/data/pluginTemplates/v1/getCurrentTime.json
Normal file
195
projects/app/data/pluginTemplates/v1/getCurrentTime.json
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
{
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "tools",
|
||||||
|
"name": "获取当前时间",
|
||||||
|
"avatar": "/imgs/module/getCurrentTime.svg",
|
||||||
|
"intro": "获取用户当前时区的时间。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": true,
|
||||||
|
"weight": 10,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "m8dupj",
|
||||||
|
"name": "定义插件输入",
|
||||||
|
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
||||||
|
"avatar": "/imgs/module/input.png",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 187.94161749205568,
|
||||||
|
"y": 179.78772129776746
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "pluginStart",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "插件开始运行",
|
||||||
|
"description": "插件开始运行时,会输出一个 True 的标识。有时候,插件不会有额外的的输入,为了顺利的进入下一个阶段,你可以将该值连接到下一个节点的触发器中。",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "pluginStart",
|
||||||
|
"label": "插件开始运行",
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "cv13yt",
|
||||||
|
"key": "switch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "bjsa7r",
|
||||||
|
"name": "定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "/imgs/module/output.png",
|
||||||
|
"flowType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1176.9471084832217,
|
||||||
|
"y": 138.94098316727695
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "time",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "time",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": false,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "time",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "time",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "cv13yt",
|
||||||
|
"name": "文本加工",
|
||||||
|
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
|
||||||
|
"avatar": "/imgs/module/textEditor.svg",
|
||||||
|
"flowType": "pluginModule",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 600.7190079155914,
|
||||||
|
"y": 1.4754510232677944
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "pluginId",
|
||||||
|
"type": "hidden",
|
||||||
|
"label": "",
|
||||||
|
"value": "community-textEditor",
|
||||||
|
"valueType": "string",
|
||||||
|
"connected": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "triggerAndFinish",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "textarea",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "文本内容",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": true,
|
||||||
|
"description": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
|
||||||
|
"edit": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": false,
|
||||||
|
"placeholder": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
|
||||||
|
"value": "{{cTime}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "需要加工的输入",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"required": false,
|
||||||
|
"description": "可动态的添加字符串类型变量,在文本编辑中通过 {{key}} 使用变量。非字符串类型,会自动转成字符串类型。",
|
||||||
|
"edit": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"type": "source",
|
||||||
|
"edit": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "bjsa7r",
|
||||||
|
"key": "time"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "",
|
||||||
|
"description": "",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
331
projects/app/data/pluginTemplates/v1/textEditor.json
Normal file
331
projects/app/data/pluginTemplates/v1/textEditor.json
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
{
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "tools",
|
||||||
|
"name": "文本加工",
|
||||||
|
"avatar": "/imgs/module/textEditor.svg",
|
||||||
|
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": false,
|
||||||
|
"weight": 100,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "w90mfp",
|
||||||
|
"name": "定义插件输入",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 616.4226348688949,
|
||||||
|
"y": -165.05298493910115
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "textarea",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "文本内容",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": true,
|
||||||
|
"description": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "需要加工的输入",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"required": false,
|
||||||
|
"description": "可动态的添加字符串类型变量,在文本编辑中通过 {{key}} 使用变量。非字符串类型,会自动转成字符串类型。",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "textarea",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "文本内容",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "需要加工的输入",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "DYNAMIC_INPUT_KEY"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"name": "定义插件输出",
|
||||||
|
"flowType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1607.7142331269126,
|
||||||
|
"y": -145.93201540017395
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": false,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"name": "HTTP模块",
|
||||||
|
"flowType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1086.8929621216014,
|
||||||
|
"y": -451.7550009773506
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"label": "GET",
|
||||||
|
"value": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "POST",
|
||||||
|
"value": "POST"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"value": "/api/plugins/textEditor",
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"text\": \"{{text}}\"\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.inputType.dynamicTargetInput",
|
||||||
|
"description": "core.module.input.description.dynamic input",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"hideInApp": true,
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "text",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "addOutputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"targets": [],
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"outputType": "source",
|
||||||
|
"valueType": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "text",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
369
projects/app/data/pluginTemplates/v1/tfSwitch.json
Normal file
369
projects/app/data/pluginTemplates/v1/tfSwitch.json
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
{
|
||||||
|
"abandon": true,
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "tools",
|
||||||
|
"name": "判断器",
|
||||||
|
"avatar": "/imgs/module/tfSwitch.svg",
|
||||||
|
"intro": "根据传入的内容进行 True False 输出。默认情况下,当传入的内容为 false, undefined, null, 0, none 时,会输出 false。你也可以增加一些自定义的字符串来补充输出 false 的内容。非字符、非数字、非布尔类型,直接输出 True。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": false,
|
||||||
|
"weight": 10,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "w90mfp",
|
||||||
|
"name": "定义插件输入",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 616.4226348688949,
|
||||||
|
"y": -165.05298493910115
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "input",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.TFSwitch input tip",
|
||||||
|
"required": true,
|
||||||
|
"edit": true,
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rule",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.input.label.TFSwitch textarea",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.TFSwitch textarea",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "input",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.input.label.TFSwitch input tip",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "8kld99",
|
||||||
|
"key": "input"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rule",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.input.label.TFSwitch textarea",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "8kld99",
|
||||||
|
"key": "rule"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"name": "定义插件输出",
|
||||||
|
"flowType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1985.3791673445353,
|
||||||
|
"y": -144.90535546692078
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "true",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "True",
|
||||||
|
"required": true,
|
||||||
|
"edit": true,
|
||||||
|
"connected": true,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "false",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "False",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": false,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "true",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "True",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "false",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "False",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "8kld99",
|
||||||
|
"name": "HTTP模块",
|
||||||
|
"flowType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1210.560012858087,
|
||||||
|
"y": -387.62433050951756
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"label": "GET",
|
||||||
|
"value": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "POST",
|
||||||
|
"value": "POST"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"value": "/api/plugins/TFSwitch",
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"input\": \"{{input}}\",\r\n \"rule\": \"{{rule}}\"\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.inputType.dynamicTargetInput",
|
||||||
|
"description": "core.module.input.description.dynamic input",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"hideInApp": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "input",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "input",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rule",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "rule",
|
||||||
|
"type": "target",
|
||||||
|
"required": false,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "addOutputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"targets": [],
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"outputType": "source",
|
||||||
|
"valueType": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "true",
|
||||||
|
"label": "true",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"key": "true"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "false",
|
||||||
|
"label": "false",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"key": "false"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -63,7 +63,10 @@ export async function getInitConfig() {
|
|||||||
initSystemConfig(),
|
initSystemConfig(),
|
||||||
// getSimpleModeTemplates(),
|
// getSimpleModeTemplates(),
|
||||||
getSystemVersion(),
|
getSystemVersion(),
|
||||||
getSystemPlugin()
|
getSystemPlugin(),
|
||||||
|
|
||||||
|
// abandon
|
||||||
|
getSystemPluginV1()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
@ -164,3 +167,29 @@ function getSystemPlugin() {
|
|||||||
|
|
||||||
global.communityPlugins = fileTemplates;
|
global.communityPlugins = fileTemplates;
|
||||||
}
|
}
|
||||||
|
function getSystemPluginV1() {
|
||||||
|
if (global.communityPluginsV1 && global.communityPluginsV1.length > 0) return;
|
||||||
|
|
||||||
|
const basePath =
|
||||||
|
process.env.NODE_ENV === 'development'
|
||||||
|
? 'data/pluginTemplates/v1'
|
||||||
|
: '/app/data/pluginTemplates/v1';
|
||||||
|
// read data/pluginTemplates directory, get all json file
|
||||||
|
const files = readdirSync(basePath);
|
||||||
|
// filter json file
|
||||||
|
const filterFiles = files.filter((item) => item.endsWith('.json'));
|
||||||
|
|
||||||
|
// read json file
|
||||||
|
const fileTemplates: (PluginTemplateType & { weight: number })[] = filterFiles.map((filename) => {
|
||||||
|
const content = readFileSync(`${basePath}/${filename}`, 'utf-8');
|
||||||
|
return {
|
||||||
|
...JSON.parse(content),
|
||||||
|
id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`,
|
||||||
|
source: PluginSourceEnum.community
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
fileTemplates.sort((a, b) => b.weight - a.weight);
|
||||||
|
|
||||||
|
global.communityPluginsV1 = fileTemplates;
|
||||||
|
}
|
||||||
|
|||||||
72
projects/app/src/pages/api/plugins/TFSwitch/index.ts
Normal file
72
projects/app/src/pages/api/plugins/TFSwitch/index.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
// @ts-ignore
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
|
|
||||||
|
type Props = HttpBodyType<{
|
||||||
|
input: string;
|
||||||
|
rule?: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const { input, rule = '' } = req.body as Props;
|
||||||
|
|
||||||
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
|
const result = (() => {
|
||||||
|
if (typeof input === 'string') {
|
||||||
|
const defaultReg: any[] = [
|
||||||
|
'',
|
||||||
|
undefined,
|
||||||
|
'undefined',
|
||||||
|
null,
|
||||||
|
'null',
|
||||||
|
false,
|
||||||
|
'false',
|
||||||
|
0,
|
||||||
|
'0',
|
||||||
|
'none'
|
||||||
|
];
|
||||||
|
const customReg = rule.split('\n');
|
||||||
|
defaultReg.push(...customReg);
|
||||||
|
|
||||||
|
return !defaultReg.find((item) => {
|
||||||
|
const reg = typeof item === 'string' ? stringToRegex(item) : null;
|
||||||
|
if (reg) {
|
||||||
|
return reg.test(input);
|
||||||
|
}
|
||||||
|
return input === item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!input;
|
||||||
|
})();
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
...(result
|
||||||
|
? {
|
||||||
|
true: true
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
false: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).send(getErrText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToRegex(str: string) {
|
||||||
|
const regexFormat = /^\/(.+)\/([gimuy]*)$/;
|
||||||
|
const match = str.match(regexFormat);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const [, pattern, flags] = match;
|
||||||
|
return new RegExp(pattern, flags);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,36 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
|
//@ts-ignore
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
|
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
|
||||||
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
|
|
||||||
type Props = HttpBodyType<{
|
type Props = HttpBodyType<{
|
||||||
|
appId: string;
|
||||||
|
chatId?: string;
|
||||||
|
responseChatItemId?: string;
|
||||||
|
defaultFeedback: string;
|
||||||
customFeedback: string;
|
customFeedback: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
customFeedback,
|
appId,
|
||||||
system_addInputParam: { appId, chatId, responseChatItemId: chatItemId }
|
chatId,
|
||||||
|
responseChatItemId: chatItemId,
|
||||||
|
defaultFeedback,
|
||||||
|
customFeedback
|
||||||
} = req.body as Props;
|
} = req.body as Props;
|
||||||
|
|
||||||
await authRequestFromLocal({ req });
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
if (!customFeedback) {
|
const feedback = customFeedback || defaultFeedback;
|
||||||
return res.json({});
|
|
||||||
|
if (!feedback) {
|
||||||
|
return res.json({
|
||||||
|
response: ''
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait the chat finish
|
// wait the chat finish
|
||||||
@ -28,17 +39,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
appId,
|
appId,
|
||||||
chatId,
|
chatId,
|
||||||
chatItemId,
|
chatItemId,
|
||||||
feedbacks: [customFeedback]
|
feedbacks: [feedback]
|
||||||
});
|
});
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
if (!chatId || !chatItemId) {
|
if (!chatId || !chatItemId) {
|
||||||
return res.json({
|
return res.json({
|
||||||
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`
|
response: `\\n\\n**自动反馈调试**: ${feedback}\\n\\n`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json({});
|
return res.json({
|
||||||
|
response: ''
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res.status(500).send(getErrText(err));
|
res.status(500).send(getErrText(err));
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
|
||||||
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
|
||||||
|
type Props = HttpBodyType<{
|
||||||
|
customFeedback: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
customFeedback,
|
||||||
|
[NodeInputKeyEnum.addInputParam]: { appId, chatId, responseChatItemId: chatItemId }
|
||||||
|
} = req.body as Props;
|
||||||
|
|
||||||
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
|
if (!customFeedback) {
|
||||||
|
return res.json({});
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait the chat finish
|
||||||
|
setTimeout(() => {
|
||||||
|
addCustomFeedbacks({
|
||||||
|
appId,
|
||||||
|
chatId,
|
||||||
|
chatItemId,
|
||||||
|
feedbacks: [customFeedback]
|
||||||
|
});
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
if (!chatId || !chatItemId) {
|
||||||
|
return res.json({
|
||||||
|
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).send(getErrText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
|
//@ts-ignore
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||||
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
|
|
||||||
type Props = HttpBodyType<{
|
type Props = HttpBodyType<{
|
||||||
text: string;
|
text: string;
|
||||||
@ -12,7 +12,10 @@ type Props = HttpBodyType<{
|
|||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const { text, [NodeInputKeyEnum.addInputParam]: obj } = req.body as Props;
|
const {
|
||||||
|
text,
|
||||||
|
DYNAMIC_INPUT_KEY: { ...obj }
|
||||||
|
} = req.body as Props;
|
||||||
|
|
||||||
await authRequestFromLocal({ req });
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
|
|||||||
42
projects/app/src/pages/api/plugins/textEditor/v2/index.ts
Normal file
42
projects/app/src/pages/api/plugins/textEditor/v2/index.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||||
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
|
||||||
|
type Props = HttpBodyType<{
|
||||||
|
text: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const { text, [NodeInputKeyEnum.addInputParam]: obj } = req.body as Props;
|
||||||
|
|
||||||
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
|
// string all value
|
||||||
|
Object.keys(obj).forEach((key) => {
|
||||||
|
let val = obj[key];
|
||||||
|
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
val = JSON.stringify(val);
|
||||||
|
} else if (typeof val === 'number') {
|
||||||
|
val = String(val);
|
||||||
|
} else if (typeof val === 'boolean') {
|
||||||
|
val = val ? 'true' : 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[key] = val;
|
||||||
|
});
|
||||||
|
|
||||||
|
const textResult = replaceVariable(text, obj);
|
||||||
|
res.json({
|
||||||
|
text: textResult
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).send(getErrText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user