Commit 05bf1b22 by Archer Committed by GitHub

V4.6.5-alpha (#609)

parent dd7b4b98
...@@ -24,7 +24,9 @@ weight: 860 ...@@ -24,7 +24,9 @@ weight: 860
"success": true, "success": true,
"message": "错误提示", "message": "错误提示",
"msg": "同message, 错误提示", "msg": "同message, 错误提示",
"uid": "用户唯一凭证" "data": {
"uid": "用户唯一凭证"
}
} }
``` ```
...@@ -80,7 +82,9 @@ curl --location --request POST '{{host}}/shareAuth/init' \ ...@@ -80,7 +82,9 @@ curl --location --request POST '{{host}}/shareAuth/init' \
```json ```json
{ {
"success": true, "success": true,
"uid": "username123", "data": {
"uid": "用户唯一凭证"
}
} }
``` ```
...@@ -129,7 +133,9 @@ curl --location --request POST '{{host}}/shareAuth/start' \ ...@@ -129,7 +133,9 @@ curl --location --request POST '{{host}}/shareAuth/start' \
```json ```json
{ {
"success": true, "success": true,
"uid": "username123", "data": {
"uid": "用户唯一凭证"
}
} }
``` ```
......
...@@ -32,7 +32,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv464' \ ...@@ -32,7 +32,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv464' \
4. 优化 - 历史记录模块。弃用旧的历史记录模块,直接在对应地方填写数值即可。 4. 优化 - 历史记录模块。弃用旧的历史记录模块,直接在对应地方填写数值即可。
5. 调整 - 知识库搜索模块 topk 逻辑,采用 MaxToken 计算,兼容不同长度的文本块 5. 调整 - 知识库搜索模块 topk 逻辑,采用 MaxToken 计算,兼容不同长度的文本块
6. 调整鉴权顺序,提高 apikey 的优先级,避免cookie抢占 apikey 的鉴权。 6. 调整鉴权顺序,提高 apikey 的优先级,避免cookie抢占 apikey 的鉴权。
7. 链接读取支持多选择器。参考[Web 站点同步用法](/docs/course/webSync) 7. 链接读取支持多选择器。参考[Web 站点同步用法](/docs/course/websync)
8. 修复 - 分享链接图片上传鉴权问题 8. 修复 - 分享链接图片上传鉴权问题
9. 修复 - Mongo 连接池未释放问题。 9. 修复 - Mongo 连接池未释放问题。
10. 修复 - Dataset Intro 无法更新 10. 修复 - Dataset Intro 无法更新
......
...@@ -84,12 +84,14 @@ export type ChatHistoryItemType = HistoryItemType & { ...@@ -84,12 +84,14 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */ /* ------- response data ------------ */
export type moduleDispatchResType = { export type moduleDispatchResType = {
// common
moduleLogo?: string; moduleLogo?: string;
price?: number; price?: number;
runningTime?: number; runningTime?: number;
tokens?: number; tokens?: number;
model?: string; model?: string;
query?: string; query?: string;
contextTotalLen?: number;
// chat // chat
temperature?: number; temperature?: number;
...@@ -116,6 +118,12 @@ export type moduleDispatchResType = { ...@@ -116,6 +118,12 @@ export type moduleDispatchResType = {
// plugin output // plugin output
pluginOutput?: Record<string, any>; pluginOutput?: Record<string, any>;
// text editor
textOutput?: string;
// tf switch
tfSwitchResult?: boolean;
}; };
export type ChatHistoryItemResType = moduleDispatchResType & { export type ChatHistoryItemResType = moduleDispatchResType & {
......
import { VectorModelItemType } from '../ai/model.d'; import { VectorModelItemType } from '../ai/model.d';
export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[]; export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[];
export type HttpBodyType<T = any> = {
appId: string;
chatId?: string;
variables: Record<string, any>;
data: T;
};
export type HttpQueryType = {
appId: string;
chatId?: string;
variables: Record<string, any>;
[key: string]: any;
};
export enum ModuleTemplateTypeEnum { export enum ModuleTemplateTypeEnum {
userGuide = 'userGuide', userGuide = 'userGuide',
systemInput = 'systemInput', systemInput = 'systemInput',
tools = 'tools',
textAnswer = 'textAnswer', textAnswer = 'textAnswer',
dataset = 'dataset',
functionCall = 'functionCall', functionCall = 'functionCall',
externalCall = 'externalCall', externalCall = 'externalCall',
personalPlugin = 'personalPlugin', personalPlugin = 'personalPlugin',
communityPlugin = 'communityPlugin',
commercialPlugin = 'commercialPlugin',
other = 'other' other = 'other'
} }
export enum ModuleDataTypeEnum { export enum ModuleIOValueTypeEnum {
string = 'string', string = 'string',
number = 'number', number = 'number',
boolean = 'boolean', boolean = 'boolean',
...@@ -44,6 +42,9 @@ export enum ModuleInputKeyEnum { ...@@ -44,6 +42,9 @@ export enum ModuleInputKeyEnum {
aiModel = 'model', aiModel = 'model',
aiSystemPrompt = 'systemPrompt', aiSystemPrompt = 'systemPrompt',
description = 'description', description = 'description',
anyInput = 'system_anyInput',
textareaInput = 'system_textareaInput',
addInputParam = 'system_addInputParam',
// history // history
historyMaxAmount = 'maxContext', historyMaxAmount = 'maxContext',
...@@ -69,7 +70,10 @@ export enum ModuleInputKeyEnum { ...@@ -69,7 +70,10 @@ export enum ModuleInputKeyEnum {
extractKeys = 'extractKeys', extractKeys = 'extractKeys',
// http // http
httpUrl = 'url', httpReqUrl = 'system_httpReqUrl',
httpHeader = 'system_httpHeader',
httpMethod = 'system_httpMethod',
abandon_httpUrl = 'url',
// app // app
runAppSelectApp = 'app', runAppSelectApp = 'app',
...@@ -87,6 +91,8 @@ export enum ModuleOutputKeyEnum { ...@@ -87,6 +91,8 @@ export enum ModuleOutputKeyEnum {
answerText = 'answerText', // answer module text key answerText = 'answerText', // answer module text key
success = 'success', success = 'success',
failed = 'failed', failed = 'failed',
text = 'system_text',
addOutputParam = 'system_addOutputParam',
// dataset // dataset
datasetIsEmpty = 'isEmpty', datasetIsEmpty = 'isEmpty',
...@@ -94,7 +100,11 @@ export enum ModuleOutputKeyEnum { ...@@ -94,7 +100,11 @@ export enum ModuleOutputKeyEnum {
datasetQuoteQA = 'quoteQA', datasetQuoteQA = 'quoteQA',
// context extract // context extract
contextExtractFields = 'fields' contextExtractFields = 'fields',
// tf switch
resultTrue = 'system_resultTrue',
resultFalse = 'system_resultFalse'
} }
export enum VariableInputEnum { export enum VariableInputEnum {
...@@ -102,3 +112,5 @@ export enum VariableInputEnum { ...@@ -102,3 +112,5 @@ export enum VariableInputEnum {
textarea = 'textarea', textarea = 'textarea',
select = 'select' select = 'select'
} }
export const DYNAMIC_INPUT_KEY = 'DYNAMIC_INPUT_KEY';
...@@ -2,32 +2,39 @@ export enum FlowNodeInputTypeEnum { ...@@ -2,32 +2,39 @@ export enum FlowNodeInputTypeEnum {
systemInput = 'systemInput', // history, userChatInput, variableInput systemInput = 'systemInput', // history, userChatInput, variableInput
input = 'input', // one line input input = 'input', // one line input
textarea = 'textarea',
numberInput = 'numberInput', numberInput = 'numberInput',
select = 'select', select = 'select',
slider = 'slider', slider = 'slider',
custom = 'custom',
target = 'target', // data input target = 'target', // data input
switch = 'switch', switch = 'switch',
textarea = 'textarea',
addInputParam = 'addInputParam', // params input
selectApp = 'selectApp', selectApp = 'selectApp',
// chat special input // chat special input
aiSettings = 'aiSettings', aiSettings = 'aiSettings',
// model select // ai model select
selectChatModel = 'selectChatModel', selectChatModel = 'selectChatModel',
selectCQModel = 'selectCQModel', selectCQModel = 'selectCQModel',
selectExtractModel = 'selectExtractModel',
// dataset special input // dataset special input
selectDataset = 'selectDataset', selectDataset = 'selectDataset',
selectDatasetParamsModal = 'selectDatasetParamsModal', selectDatasetParamsModal = 'selectDatasetParamsModal',
hidden = 'hidden' hidden = 'hidden',
custom = 'custom'
} }
export enum FlowNodeOutputTypeEnum { export enum FlowNodeOutputTypeEnum {
answer = 'answer', answer = 'answer',
source = 'source', source = 'source',
hidden = 'hidden' hidden = 'hidden',
addOutputParam = 'addOutputParam'
} }
export enum FlowNodeTypeEnum { export enum FlowNodeTypeEnum {
...@@ -45,7 +52,10 @@ export enum FlowNodeTypeEnum { ...@@ -45,7 +52,10 @@ export enum FlowNodeTypeEnum {
pluginModule = 'pluginModule', pluginModule = 'pluginModule',
pluginInput = 'pluginInput', pluginInput = 'pluginInput',
pluginOutput = 'pluginOutput', pluginOutput = 'pluginOutput',
textEditor = 'textEditor',
// abandon // abandon
variable = 'variable' variable = 'variable'
} }
export const EDGE_TYPE = 'smoothstep';
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './constant'; import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './constant';
import { ModuleDataTypeEnum, ModuleInputKeyEnum, ModuleOutputKeyEnum } from '../constants'; import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleOutputKeyEnum } from '../constants';
import { SelectedDatasetType } from '../api'; import { SelectedDatasetType } from '../api';
import { EditInputFieldMap, EditOutputFieldMap } from './type';
export type FlowNodeChangeProps = { export type FlowNodeChangeProps = {
moduleId: string; moduleId: string;
...@@ -20,27 +21,34 @@ export type FlowNodeChangeProps = { ...@@ -20,27 +21,34 @@ export type FlowNodeChangeProps = {
}; };
export type FlowNodeInputItemType = { export type FlowNodeInputItemType = {
valueType?: `${ModuleIOValueTypeEnum}`; // data type
type: `${FlowNodeInputTypeEnum}`; // Node Type. Decide on a render style
key: `${ModuleInputKeyEnum}` | string; key: `${ModuleInputKeyEnum}` | string;
type: `${FlowNodeInputTypeEnum}`; // Decide on a render style
value?: any; value?: any;
valueType?: `${ModuleDataTypeEnum}`; // data type
label: string; label: string;
description?: string; description?: string;
required?: boolean; required?: boolean;
edit?: boolean; // Whether to allow editing edit?: boolean; // Whether to allow editing
connected?: boolean; // unConnected field will be deleted editField?: EditInputFieldMap;
defaultEditField?: EditNodeFieldType;
connected?: boolean; // There are incoming data
showTargetInApp?: boolean; showTargetInApp?: boolean;
showTargetInPlugin?: boolean; showTargetInPlugin?: boolean;
hideInApp?: boolean;
hideInPlugin?: boolean;
placeholder?: string; // input,textarea placeholder?: string; // input,textarea
list?: { label: string; value: any }[]; // select list?: { label: string; value: any }[]; // select
step?: number; // slider max?: number;
max?: number;
min?: number;
markList?: { label: string; value: any }[]; // slider
plusField?: boolean; // plus system will show markList?: { label: string; value: any }[]; // slider
step?: number; // slider
max?: number; // slider, number input
min?: number; // slider, number input
}; };
export type FlowNodeOutputTargetItemType = { export type FlowNodeOutputTargetItemType = {
...@@ -48,15 +56,41 @@ export type FlowNodeOutputTargetItemType = { ...@@ -48,15 +56,41 @@ export type FlowNodeOutputTargetItemType = {
key: string; key: string;
}; };
export type FlowNodeOutputItemType = { export type FlowNodeOutputItemType = {
type?: `${FlowNodeOutputTypeEnum}`;
key: `${ModuleOutputKeyEnum}` | string; key: `${ModuleOutputKeyEnum}` | string;
valueType?: `${ModuleIOValueTypeEnum}`;
label?: string; label?: string;
edit?: boolean;
description?: string; description?: string;
valueType?: `${ModuleDataTypeEnum}`;
type?: `${FlowNodeOutputTypeEnum}`; edit?: boolean;
editField?: EditOutputFieldMap;
defaultEditField?: EditNodeFieldType;
targets: FlowNodeOutputTargetItemType[]; targets: FlowNodeOutputTargetItemType[];
}; };
/* --------------- edit field ------------------- */
export type EditInputFieldMap = EditOutputFieldMap & {
inputType?: boolean;
required?: boolean;
};
export type EditOutputFieldMap = {
name?: boolean;
key?: boolean;
description?: boolean;
dataType?: boolean;
};
export type EditNodeFieldType = {
inputType?: `${FlowNodeInputTypeEnum}`; // input type
outputType?: `${FlowNodeOutputTypeEnum}`;
required?: boolean;
key?: string;
label?: string;
description?: string;
valueType?: `${ModuleIOValueTypeEnum}`;
};
/* ------------- item type --------------- */ /* ------------- item type --------------- */
/* ai chat modules props */ /* ai chat modules props */
export type AIChatModuleProps = { export type AIChatModuleProps = {
......
import type { FlowNodeInputItemType } from '../node/type.d'; import type { FlowNodeInputItemType } from '../node/type.d';
import { ModuleInputKeyEnum } from '../constants'; import { DYNAMIC_INPUT_KEY, ModuleInputKeyEnum } from '../constants';
import { FlowNodeInputTypeEnum } from '../node/constant'; import { FlowNodeInputTypeEnum } from '../node/constant';
import { ModuleDataTypeEnum } from '../constants'; import { ModuleIOValueTypeEnum } from '../constants';
export const Input_Template_TFSwitch: FlowNodeInputItemType = { export const Input_Template_Switch: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.switch, key: ModuleInputKeyEnum.switch,
type: FlowNodeInputTypeEnum.target, type: FlowNodeInputTypeEnum.target,
label: 'core.module.input.label.switch', label: 'core.module.input.label.switch',
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
}; };
...@@ -19,7 +19,7 @@ export const Input_Template_History: FlowNodeInputItemType = { ...@@ -19,7 +19,7 @@ export const Input_Template_History: FlowNodeInputItemType = {
required: true, required: true,
min: 0, min: 0,
max: 30, max: 30,
valueType: ModuleDataTypeEnum.chatHistory, valueType: ModuleIOValueTypeEnum.chatHistory,
value: 6, value: 6,
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
...@@ -30,7 +30,29 @@ export const Input_Template_UserChatInput: FlowNodeInputItemType = { ...@@ -30,7 +30,29 @@ export const Input_Template_UserChatInput: FlowNodeInputItemType = {
type: FlowNodeInputTypeEnum.target, type: FlowNodeInputTypeEnum.target,
label: 'core.module.input.label.user question', label: 'core.module.input.label.user question',
required: true, required: true,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
}; };
export const Input_Template_AddInputParam: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.addInputParam,
type: FlowNodeInputTypeEnum.addInputParam,
valueType: ModuleIOValueTypeEnum.any,
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
};
export const Input_Template_DynamicInput: FlowNodeInputItemType = {
key: DYNAMIC_INPUT_KEY,
type: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.any,
label: 'core.module.inputType.dynamicTargetInput',
description: 'core.module.input.description.dynamic input',
required: false,
showTargetInApp: false,
showTargetInPlugin: true,
hideInApp: true
};
import type { FlowNodeOutputItemType } from '../node/type'; import type { FlowNodeOutputItemType } from '../node/type';
import { ModuleOutputKeyEnum } from '../constants'; import { ModuleOutputKeyEnum } from '../constants';
import { FlowNodeOutputTypeEnum } from '../node/constant'; import { FlowNodeOutputTypeEnum } from '../node/constant';
import { ModuleDataTypeEnum } from '../constants'; import { ModuleIOValueTypeEnum } from '../constants';
export const Output_Template_Finish: FlowNodeOutputItemType = { export const Output_Template_Finish: FlowNodeOutputItemType = {
key: ModuleOutputKeyEnum.finish, key: ModuleOutputKeyEnum.finish,
label: 'core.module.output.label.running done', label: 'core.module.output.label.running done',
description: 'core.module.output.description.running done', description: 'core.module.output.description.running done',
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}; };
export const Output_Template_AddOutput: FlowNodeOutputItemType = {
key: ModuleOutputKeyEnum.addOutputParam,
type: FlowNodeOutputTypeEnum.addOutputParam,
valueType: ModuleIOValueTypeEnum.any,
label: '',
targets: []
};
...@@ -2,9 +2,13 @@ import { ...@@ -2,9 +2,13 @@ import {
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../../type';
import { ModuleDataTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants'; import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleTemplateTypeEnum
} from '../../../constants';
export const HistoryModule: FlowModuleTemplateType = { export const HistoryModule: FlowModuleTemplateType = {
id: FlowNodeTypeEnum.historyNode, id: FlowNodeTypeEnum.historyNode,
...@@ -12,7 +16,7 @@ export const HistoryModule: FlowModuleTemplateType = { ...@@ -12,7 +16,7 @@ export const HistoryModule: FlowModuleTemplateType = {
flowType: FlowNodeTypeEnum.historyNode, flowType: FlowNodeTypeEnum.historyNode,
avatar: '/imgs/module/history.png', avatar: '/imgs/module/history.png',
name: '聊天记录(弃用)', name: '聊天记录(弃用)',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。', intro: '聊天记录,该模块已被弃用',
inputs: [ inputs: [
{ {
key: ModuleInputKeyEnum.historyMaxAmount, key: ModuleInputKeyEnum.historyMaxAmount,
...@@ -21,7 +25,7 @@ export const HistoryModule: FlowModuleTemplateType = { ...@@ -21,7 +25,7 @@ export const HistoryModule: FlowModuleTemplateType = {
description: description:
'该记录数不代表模型可接收这么多的历史记录,具体可接收多少历史记录,取决于模型的能力,通常建议不要超过20条。', '该记录数不代表模型可接收这么多的历史记录,具体可接收多少历史记录,取决于模型的能力,通常建议不要超过20条。',
value: 6, value: 6,
valueType: ModuleDataTypeEnum.number, valueType: ModuleIOValueTypeEnum.number,
min: 0, min: 0,
max: 100, max: 100,
showTargetInApp: false, showTargetInApp: false,
...@@ -30,7 +34,7 @@ export const HistoryModule: FlowModuleTemplateType = { ...@@ -30,7 +34,7 @@ export const HistoryModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.history, key: ModuleInputKeyEnum.history,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleDataTypeEnum.chatHistory, valueType: ModuleIOValueTypeEnum.chatHistory,
label: '聊天记录', label: '聊天记录',
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
...@@ -40,7 +44,7 @@ export const HistoryModule: FlowModuleTemplateType = { ...@@ -40,7 +44,7 @@ export const HistoryModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.history, key: ModuleInputKeyEnum.history,
label: '聊天记录', label: '聊天记录',
valueType: ModuleDataTypeEnum.chatHistory, valueType: ModuleIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
} }
......
...@@ -5,14 +5,14 @@ import { ...@@ -5,14 +5,14 @@ import {
} from '../../node/constant'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { import {
ModuleDataTypeEnum, ModuleIOValueTypeEnum,
ModuleInputKeyEnum, ModuleInputKeyEnum,
ModuleOutputKeyEnum, ModuleOutputKeyEnum,
ModuleTemplateTypeEnum ModuleTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { import {
Input_Template_History, Input_Template_History,
Input_Template_TFSwitch, Input_Template_Switch,
Input_Template_UserChatInput Input_Template_UserChatInput
} from '../input'; } from '../input';
import { chatNodeSystemPromptTip } from '../tip'; import { chatNodeSystemPromptTip } from '../tip';
...@@ -27,13 +27,13 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -27,13 +27,13 @@ export const AiChatModule: FlowModuleTemplateType = {
intro: 'AI 大模型对话', intro: 'AI 大模型对话',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.aiModel, key: ModuleInputKeyEnum.aiModel,
type: FlowNodeInputTypeEnum.selectChatModel, type: FlowNodeInputTypeEnum.selectChatModel,
label: '对话模型', label: '对话模型',
required: true, required: true,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -43,7 +43,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -43,7 +43,7 @@ export const AiChatModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window
label: '温度', label: '温度',
value: 0, value: 0,
valueType: ModuleDataTypeEnum.number, valueType: ModuleIOValueTypeEnum.number,
min: 0, min: 0,
max: 10, max: 10,
step: 1, step: 1,
...@@ -59,7 +59,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -59,7 +59,7 @@ export const AiChatModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window
label: '回复上限', label: '回复上限',
value: 2000, value: 2000,
valueType: ModuleDataTypeEnum.number, valueType: ModuleIOValueTypeEnum.number,
min: 100, min: 100,
max: 4000, max: 4000,
step: 50, step: 50,
...@@ -78,7 +78,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -78,7 +78,7 @@ export const AiChatModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
label: '返回AI内容', label: '返回AI内容',
value: true, value: true,
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -86,7 +86,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -86,7 +86,7 @@ export const AiChatModule: FlowModuleTemplateType = {
key: ModuleInputKeyEnum.aiChatQuoteTemplate, key: ModuleInputKeyEnum.aiChatQuoteTemplate,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
label: '引用内容模板', label: '引用内容模板',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -94,7 +94,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -94,7 +94,7 @@ export const AiChatModule: FlowModuleTemplateType = {
key: ModuleInputKeyEnum.aiChatQuotePrompt, key: ModuleInputKeyEnum.aiChatQuotePrompt,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
label: '引用内容提示词', label: '引用内容提示词',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -102,7 +102,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -102,7 +102,7 @@ export const AiChatModule: FlowModuleTemplateType = {
key: ModuleInputKeyEnum.aiChatSettingModal, key: ModuleInputKeyEnum.aiChatSettingModal,
type: FlowNodeInputTypeEnum.aiSettings, type: FlowNodeInputTypeEnum.aiSettings,
label: '', label: '',
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -112,7 +112,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -112,7 +112,7 @@ export const AiChatModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.textarea, type: FlowNodeInputTypeEnum.textarea,
label: '系统提示词', label: '系统提示词',
max: 300, max: 300,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
description: chatNodeSystemPromptTip, description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip, placeholder: chatNodeSystemPromptTip,
showTargetInApp: true, showTargetInApp: true,
...@@ -124,7 +124,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -124,7 +124,7 @@ export const AiChatModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.target, type: FlowNodeInputTypeEnum.target,
label: '引用内容', label: '引用内容',
description: "对象数组格式,结构:\n [{q:'问题',a:'回答'}]", description: "对象数组格式,结构:\n [{q:'问题',a:'回答'}]",
valueType: ModuleDataTypeEnum.datasetQuote, valueType: ModuleIOValueTypeEnum.datasetQuote,
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
}, },
...@@ -135,7 +135,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -135,7 +135,7 @@ export const AiChatModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.history, key: ModuleOutputKeyEnum.history,
label: '新的上下文', label: '新的上下文',
description: '将本次回复内容拼接上历史记录,作为新的上下文返回', description: '将本次回复内容拼接上历史记录,作为新的上下文返回',
valueType: ModuleDataTypeEnum.chatHistory, valueType: ModuleIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}, },
...@@ -143,7 +143,7 @@ export const AiChatModule: FlowModuleTemplateType = { ...@@ -143,7 +143,7 @@ export const AiChatModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.answerText, key: ModuleOutputKeyEnum.answerText,
label: 'AI回复', label: 'AI回复',
description: '将在 stream 回复完毕后触发', description: '将在 stream 回复完毕后触发',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}, },
......
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { ModuleDataTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants'; import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants';
import { Input_Template_TFSwitch } from '../input'; import { Input_Template_Switch } from '../input';
import { Output_Template_Finish } from '../output'; import { Output_Template_Finish } from '../output';
export const AssignedAnswerModule: FlowModuleTemplateType = { export const AssignedAnswerModule: FlowModuleTemplateType = {
...@@ -12,14 +12,16 @@ export const AssignedAnswerModule: FlowModuleTemplateType = { ...@@ -12,14 +12,16 @@ export const AssignedAnswerModule: FlowModuleTemplateType = {
name: '指定回复', name: '指定回复',
intro: '该模块可以直接回复一段指定的内容。常用于引导、提示', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示',
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.answerText, key: ModuleInputKeyEnum.answerText,
type: FlowNodeInputTypeEnum.textarea, type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
label: '回复的内容', label: '回复的内容',
description: description:
'可以使用 \\n 来实现连续换行。\n\n可以通过外部模块输入实现回复,外部模块输入时会覆盖当前填写的内容。\n\n如传入非字符串类型数据将会自动转成字符串', '可以使用 \\n 来实现连续换行。\n可以通过外部模块输入实现回复,外部模块输入时会覆盖当前填写的内容。\n如传入非字符串类型数据将会自动转成字符串',
placeholder:
'可以使用 \\n 来实现连续换行。\n可以通过外部模块输入实现回复,外部模块输入时会覆盖当前填写的内容。\n如传入非字符串类型数据将会自动转成字符串',
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
} }
......
...@@ -4,10 +4,10 @@ import { ...@@ -4,10 +4,10 @@ import {
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { ModuleDataTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants'; import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants';
import { import {
Input_Template_History, Input_Template_History,
Input_Template_TFSwitch, Input_Template_Switch,
Input_Template_UserChatInput Input_Template_UserChatInput
} from '../input'; } from '../input';
...@@ -24,11 +24,11 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = { ...@@ -24,11 +24,11 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
类型4: 其他问题`, 类型4: 其他问题`,
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.aiModel, key: ModuleInputKeyEnum.aiModel,
type: FlowNodeInputTypeEnum.selectCQModel, type: FlowNodeInputTypeEnum.selectCQModel,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '分类模型', label: '分类模型',
required: true, required: true,
showTargetInApp: false, showTargetInApp: false,
...@@ -37,7 +37,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = { ...@@ -37,7 +37,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.aiSystemPrompt, key: ModuleInputKeyEnum.aiSystemPrompt,
type: FlowNodeInputTypeEnum.textarea, type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '背景知识', label: '背景知识',
description: description:
'你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。', '你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。',
...@@ -51,7 +51,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = { ...@@ -51,7 +51,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.agents, key: ModuleInputKeyEnum.agents,
type: FlowNodeInputTypeEnum.custom, type: FlowNodeInputTypeEnum.custom,
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
label: '', label: '',
value: [ value: [
{ {
......
...@@ -5,12 +5,12 @@ import { ...@@ -5,12 +5,12 @@ import {
} from '../../node/constant'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { import {
ModuleDataTypeEnum, ModuleIOValueTypeEnum,
ModuleInputKeyEnum, ModuleInputKeyEnum,
ModuleOutputKeyEnum, ModuleOutputKeyEnum,
ModuleTemplateTypeEnum ModuleTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { Input_Template_History, Input_Template_TFSwitch } from '../input'; import { Input_Template_History, Input_Template_Switch } from '../input';
export const ContextExtractModule: FlowModuleTemplateType = { export const ContextExtractModule: FlowModuleTemplateType = {
id: FlowNodeTypeEnum.contentExtract, id: FlowNodeTypeEnum.contentExtract,
...@@ -21,11 +21,20 @@ export const ContextExtractModule: FlowModuleTemplateType = { ...@@ -21,11 +21,20 @@ export const ContextExtractModule: FlowModuleTemplateType = {
intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等', intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{
key: ModuleInputKeyEnum.aiModel,
type: FlowNodeInputTypeEnum.selectExtractModel,
valueType: ModuleIOValueTypeEnum.string,
label: '提取模型',
required: true,
showTargetInApp: false,
showTargetInPlugin: false
},
{ {
key: ModuleInputKeyEnum.description, key: ModuleInputKeyEnum.description,
type: FlowNodeInputTypeEnum.textarea, type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '提取要求描述', label: '提取要求描述',
description: '给AI一些对应的背景知识或要求描述,引导AI更好的完成任务', description: '给AI一些对应的背景知识或要求描述,引导AI更好的完成任务',
required: true, required: true,
...@@ -40,7 +49,7 @@ export const ContextExtractModule: FlowModuleTemplateType = { ...@@ -40,7 +49,7 @@ export const ContextExtractModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.target, type: FlowNodeInputTypeEnum.target,
label: '需要提取的文本', label: '需要提取的文本',
required: true, required: true,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
}, },
...@@ -48,9 +57,9 @@ export const ContextExtractModule: FlowModuleTemplateType = { ...@@ -48,9 +57,9 @@ export const ContextExtractModule: FlowModuleTemplateType = {
key: ModuleInputKeyEnum.extractKeys, key: ModuleInputKeyEnum.extractKeys,
type: FlowNodeInputTypeEnum.custom, type: FlowNodeInputTypeEnum.custom,
label: '目标字段', label: '目标字段',
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段", description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
value: [], // {desc: string; key: string; required: boolean;}[] value: [], // {desc: string; key: string; required: boolean; enum: string[]}[]
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
} }
...@@ -59,14 +68,14 @@ export const ContextExtractModule: FlowModuleTemplateType = { ...@@ -59,14 +68,14 @@ export const ContextExtractModule: FlowModuleTemplateType = {
{ {
key: ModuleOutputKeyEnum.success, key: ModuleOutputKeyEnum.success,
label: '字段完全提取', label: '字段完全提取',
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}, },
{ {
key: ModuleOutputKeyEnum.failed, key: ModuleOutputKeyEnum.failed,
label: '提取字段缺失', label: '提取字段缺失',
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}, },
...@@ -74,7 +83,7 @@ export const ContextExtractModule: FlowModuleTemplateType = { ...@@ -74,7 +83,7 @@ export const ContextExtractModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.contextExtractFields, key: ModuleOutputKeyEnum.contextExtractFields,
label: '完整提取结果', label: '完整提取结果',
description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}', description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
} }
......
...@@ -5,31 +5,31 @@ import { ...@@ -5,31 +5,31 @@ import {
} from '../../node/constant'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { import {
ModuleDataTypeEnum, ModuleIOValueTypeEnum,
ModuleInputKeyEnum, ModuleInputKeyEnum,
ModuleOutputKeyEnum, ModuleOutputKeyEnum,
ModuleTemplateTypeEnum ModuleTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { Input_Template_TFSwitch, Input_Template_UserChatInput } from '../input'; import { Input_Template_Switch, Input_Template_UserChatInput } from '../input';
import { Output_Template_Finish } from '../output'; import { Output_Template_Finish } from '../output';
import { DatasetSearchModeEnum } from '../../../dataset/constant'; import { DatasetSearchModeEnum } from '../../../dataset/constant';
export const DatasetSearchModule: FlowModuleTemplateType = { export const DatasetSearchModule: FlowModuleTemplateType = {
id: FlowNodeTypeEnum.datasetSearchNode, id: FlowNodeTypeEnum.datasetSearchNode,
templateType: ModuleTemplateTypeEnum.dataset, templateType: ModuleTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.datasetSearchNode, flowType: FlowNodeTypeEnum.datasetSearchNode,
avatar: '/imgs/module/db.png', avatar: '/imgs/module/db.png',
name: '知识库搜索', name: '知识库搜索',
intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。', intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.datasetSelectList, key: ModuleInputKeyEnum.datasetSelectList,
type: FlowNodeInputTypeEnum.selectDataset, type: FlowNodeInputTypeEnum.selectDataset,
label: '关联的知识库', label: '关联的知识库',
value: [], value: [],
valueType: ModuleDataTypeEnum.selectDataset, valueType: ModuleIOValueTypeEnum.selectDataset,
list: [], list: [],
required: true, required: true,
showTargetInApp: false, showTargetInApp: false,
...@@ -40,7 +40,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = { ...@@ -40,7 +40,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
label: '最低相关性', label: '最低相关性',
value: 0.4, value: 0.4,
valueType: ModuleDataTypeEnum.number, valueType: ModuleIOValueTypeEnum.number,
min: 0, min: 0,
max: 1, max: 1,
step: 0.01, step: 0.01,
...@@ -57,7 +57,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = { ...@@ -57,7 +57,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = {
label: '引用上限', label: '引用上限',
description: '单次搜索最大的 Tokens 数量,中文约1字=1.7Tokens,英文约1字=1Tokens', description: '单次搜索最大的 Tokens 数量,中文约1字=1.7Tokens,英文约1字=1Tokens',
value: 1500, value: 1500,
valueType: ModuleDataTypeEnum.number, valueType: ModuleIOValueTypeEnum.number,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -65,7 +65,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = { ...@@ -65,7 +65,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = {
key: ModuleInputKeyEnum.datasetSearchMode, key: ModuleInputKeyEnum.datasetSearchMode,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
label: 'core.dataset.search.Mode', label: 'core.dataset.search.Mode',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false, showTargetInPlugin: false,
value: DatasetSearchModeEnum.embedding value: DatasetSearchModeEnum.embedding
...@@ -74,7 +74,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = { ...@@ -74,7 +74,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = {
key: ModuleInputKeyEnum.datasetParamsModal, key: ModuleInputKeyEnum.datasetParamsModal,
type: FlowNodeInputTypeEnum.selectDatasetParamsModal, type: FlowNodeInputTypeEnum.selectDatasetParamsModal,
label: '', label: '',
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
}, },
...@@ -85,14 +85,14 @@ export const DatasetSearchModule: FlowModuleTemplateType = { ...@@ -85,14 +85,14 @@ export const DatasetSearchModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.datasetIsEmpty, key: ModuleOutputKeyEnum.datasetIsEmpty,
label: '搜索结果为空', label: '搜索结果为空',
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
targets: [] targets: []
}, },
{ {
key: ModuleOutputKeyEnum.datasetUnEmpty, key: ModuleOutputKeyEnum.datasetUnEmpty,
label: '搜索结果不为空', label: '搜索结果不为空',
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
targets: [] targets: []
}, },
{ {
...@@ -101,7 +101,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = { ...@@ -101,7 +101,7 @@ export const DatasetSearchModule: FlowModuleTemplateType = {
description: description:
'始终返回数组,如果希望搜索结果为空时执行额外操作,需要用到上面的两个输入以及目标模块的触发器', '始终返回数组,如果希望搜索结果为空时执行额外操作,需要用到上面的两个输入以及目标模块的触发器',
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
valueType: ModuleDataTypeEnum.datasetQuote, valueType: ModuleIOValueTypeEnum.datasetQuote,
targets: [] targets: []
}, },
Output_Template_Finish Output_Template_Finish
......
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant'; import {
import { FlowModuleTemplateType } from '../../type.d'; FlowNodeInputTypeEnum,
import { ModuleDataTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants'; FlowNodeOutputTypeEnum,
import { Input_Template_TFSwitch } from '../input'; FlowNodeTypeEnum
import { Output_Template_Finish } from '../output'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type';
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants';
import {
Input_Template_AddInputParam,
Input_Template_DynamicInput,
Input_Template_Switch
} from '../input';
import { Output_Template_AddOutput, Output_Template_Finish } from '../output';
export const HttpModule: FlowModuleTemplateType = { export const HttpModule: FlowModuleTemplateType = {
id: FlowNodeTypeEnum.httpRequest, id: FlowNodeTypeEnum.httpRequest,
...@@ -13,18 +21,86 @@ export const HttpModule: FlowModuleTemplateType = { ...@@ -13,18 +21,86 @@ export const HttpModule: FlowModuleTemplateType = {
intro: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)', intro: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.httpUrl, key: ModuleInputKeyEnum.httpMethod,
type: FlowNodeInputTypeEnum.select,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.module.input.label.Http Request Method',
value: 'POST',
list: [
{
label: 'GET',
value: 'GET'
},
{
label: 'POST',
value: 'POST'
}
],
required: true,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpReqUrl,
type: FlowNodeInputTypeEnum.input, type: FlowNodeInputTypeEnum.input,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '请求地址', label: 'core.module.input.label.Http Request Url',
description: '请求目标地址', description: 'core.module.input.description.Http Request Url',
placeholder: 'https://api.ai.com/getInventory', placeholder: 'https://api.ai.com/getInventory',
required: true, required: false,
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpHeader,
type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.module.input.label.Http Request Header',
description: 'core.module.input.description.Http Request Header',
placeholder: 'core.module.input.description.Http Request Header',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
Input_Template_DynamicInput,
{
...Input_Template_AddInputParam,
editField: {
key: true,
name: true,
description: true,
required: true,
dataType: true
},
defaultEditField: {
label: '',
key: '',
description: '',
inputType: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string,
required: true
}
} }
], ],
outputs: [Output_Template_Finish] outputs: [
Output_Template_Finish,
{
...Output_Template_AddOutput,
editField: {
key: true,
name: true,
description: true,
dataType: true
},
defaultEditField: {
label: '',
key: '',
description: '',
outputType: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.string
}
}
]
}; };
...@@ -5,14 +5,14 @@ import { ...@@ -5,14 +5,14 @@ import {
} from '../../node/constant'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { import {
ModuleDataTypeEnum, ModuleIOValueTypeEnum,
ModuleInputKeyEnum, ModuleInputKeyEnum,
ModuleOutputKeyEnum, ModuleOutputKeyEnum,
ModuleTemplateTypeEnum ModuleTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { import {
Input_Template_History, Input_Template_History,
Input_Template_TFSwitch, Input_Template_Switch,
Input_Template_UserChatInput Input_Template_UserChatInput
} from '../input'; } from '../input';
import { Output_Template_Finish } from '../output'; import { Output_Template_Finish } from '../output';
...@@ -26,11 +26,11 @@ export const RunAppModule: FlowModuleTemplateType = { ...@@ -26,11 +26,11 @@ export const RunAppModule: FlowModuleTemplateType = {
intro: '可以选择一个其他应用进行调用', intro: '可以选择一个其他应用进行调用',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch, Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.runAppSelectApp, key: ModuleInputKeyEnum.runAppSelectApp,
type: FlowNodeInputTypeEnum.selectApp, type: FlowNodeInputTypeEnum.selectApp,
valueType: ModuleDataTypeEnum.selectApp, valueType: ModuleIOValueTypeEnum.selectApp,
label: '选择一个应用', label: '选择一个应用',
description: '选择一个其他应用进行调用', description: '选择一个其他应用进行调用',
required: true, required: true,
...@@ -45,7 +45,7 @@ export const RunAppModule: FlowModuleTemplateType = { ...@@ -45,7 +45,7 @@ export const RunAppModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.history, key: ModuleOutputKeyEnum.history,
label: '新的上下文', label: '新的上下文',
description: '将该应用回复内容拼接到历史记录中,作为新的上下文返回', description: '将该应用回复内容拼接到历史记录中,作为新的上下文返回',
valueType: ModuleDataTypeEnum.chatHistory, valueType: ModuleIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}, },
...@@ -53,7 +53,7 @@ export const RunAppModule: FlowModuleTemplateType = { ...@@ -53,7 +53,7 @@ export const RunAppModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.answerText, key: ModuleOutputKeyEnum.answerText,
label: 'AI回复', label: 'AI回复',
description: '将在应用完全结束后触发', description: '将在应用完全结束后触发',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}, },
......
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { userGuideTip } from '../tip'; import { userGuideTip } from '../tip';
import { ModuleDataTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants'; import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants';
export const UserGuideModule: FlowModuleTemplateType = { export const UserGuideModule: FlowModuleTemplateType = {
id: FlowNodeTypeEnum.userGuide, id: FlowNodeTypeEnum.userGuide,
...@@ -14,7 +14,7 @@ export const UserGuideModule: FlowModuleTemplateType = { ...@@ -14,7 +14,7 @@ export const UserGuideModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.welcomeText, key: ModuleInputKeyEnum.welcomeText,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '开场白', label: '开场白',
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
...@@ -22,7 +22,7 @@ export const UserGuideModule: FlowModuleTemplateType = { ...@@ -22,7 +22,7 @@ export const UserGuideModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.variables, key: ModuleInputKeyEnum.variables,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
label: '对话框变量', label: '对话框变量',
value: [], value: [],
showTargetInApp: false, showTargetInApp: false,
...@@ -30,7 +30,7 @@ export const UserGuideModule: FlowModuleTemplateType = { ...@@ -30,7 +30,7 @@ export const UserGuideModule: FlowModuleTemplateType = {
}, },
{ {
key: ModuleInputKeyEnum.questionGuide, key: ModuleInputKeyEnum.questionGuide,
valueType: ModuleDataTypeEnum.boolean, valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeInputTypeEnum.switch, type: FlowNodeInputTypeEnum.switch,
label: '问题引导', label: '问题引导',
showTargetInApp: false, showTargetInApp: false,
...@@ -39,7 +39,7 @@ export const UserGuideModule: FlowModuleTemplateType = { ...@@ -39,7 +39,7 @@ export const UserGuideModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.tts, key: ModuleInputKeyEnum.tts,
type: FlowNodeInputTypeEnum.hidden, type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleDataTypeEnum.any, valueType: ModuleIOValueTypeEnum.any,
label: '语音播报', label: '语音播报',
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
......
...@@ -5,7 +5,7 @@ import { ...@@ -5,7 +5,7 @@ import {
} from '../../node/constant'; } from '../../node/constant';
import { FlowModuleTemplateType } from '../../type.d'; import { FlowModuleTemplateType } from '../../type.d';
import { import {
ModuleDataTypeEnum, ModuleIOValueTypeEnum,
ModuleInputKeyEnum, ModuleInputKeyEnum,
ModuleOutputKeyEnum, ModuleOutputKeyEnum,
ModuleTemplateTypeEnum ModuleTemplateTypeEnum
...@@ -22,7 +22,7 @@ export const UserInputModule: FlowModuleTemplateType = { ...@@ -22,7 +22,7 @@ export const UserInputModule: FlowModuleTemplateType = {
{ {
key: ModuleInputKeyEnum.userChatInput, key: ModuleInputKeyEnum.userChatInput,
type: FlowNodeInputTypeEnum.systemInput, type: FlowNodeInputTypeEnum.systemInput,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '用户问题', label: '用户问题',
showTargetInApp: false, showTargetInApp: false,
showTargetInPlugin: false showTargetInPlugin: false
...@@ -33,7 +33,7 @@ export const UserInputModule: FlowModuleTemplateType = { ...@@ -33,7 +33,7 @@ export const UserInputModule: FlowModuleTemplateType = {
key: ModuleOutputKeyEnum.userChatInput, key: ModuleOutputKeyEnum.userChatInput,
label: '用户问题', label: '用户问题',
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
targets: [] targets: []
} }
] ]
......
import { FlowNodeTypeEnum } from './node/constant'; import { FlowNodeTypeEnum } from './node/constant';
import { ModuleDataTypeEnum, ModuleTemplateTypeEnum, VariableInputEnum } from './constants'; import { ModuleIOValueTypeEnum, ModuleTemplateTypeEnum, VariableInputEnum } from './constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type'; import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
export type FlowModuleTemplateType = { export type FlowModuleTemplateType = {
...@@ -72,4 +72,5 @@ export type ContextExtractAgentItemType = { ...@@ -72,4 +72,5 @@ export type ContextExtractAgentItemType = {
desc: string; desc: string;
key: string; key: string;
required: boolean; required: boolean;
enum?: string;
}; };
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from './node/constant'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from './node/constant';
import { ModuleDataTypeEnum, ModuleInputKeyEnum } from './constants'; import { ModuleIOValueTypeEnum, ModuleInputKeyEnum } from './constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type'; import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
import { AppTTSConfigType, ModuleItemType, VariableItemType } from './type'; import { AppTTSConfigType, ModuleItemType, VariableItemType } from './type';
import { Input_Template_Switch } from './template/input';
export const getGuideModule = (modules: ModuleItemType[]) => export const getGuideModule = (modules: ModuleItemType[]) =>
modules.find((item) => item.flowType === FlowNodeTypeEnum.userGuide); modules.find((item) => item.flowType === FlowNodeTypeEnum.userGuide);
...@@ -29,42 +30,64 @@ export const splitGuideModule = (guideModules?: ModuleItemType) => { ...@@ -29,42 +30,64 @@ export const splitGuideModule = (guideModules?: ModuleItemType) => {
}; };
}; };
export function formatPluginToPreviewModule( export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
if (input.value !== undefined || !input.valueType) return input.value;
const map: Record<string, any> = {
[ModuleIOValueTypeEnum.boolean]: false,
[ModuleIOValueTypeEnum.number]: 0,
[ModuleIOValueTypeEnum.string]: ''
};
return map[input.valueType];
};
export const getModuleInputUiField = (input: FlowNodeInputItemType) => {
if (input.type === FlowNodeInputTypeEnum.input || input.type === FlowNodeInputTypeEnum.textarea) {
return {
placeholder: input.placeholder || input.description
};
}
return {};
};
export function plugin2ModuleIO(
pluginId: string, pluginId: string,
modules: ModuleItemType[] modules: ModuleItemType[]
): { ): {
inputs: FlowNodeInputItemType[]; inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[]; outputs: FlowNodeOutputItemType[];
} { } {
function getPluginTemplatePluginIdInput(pluginId: string): FlowNodeInputItemType {
return {
key: ModuleInputKeyEnum.pluginId,
type: FlowNodeInputTypeEnum.hidden,
label: 'pluginId',
value: pluginId,
valueType: ModuleDataTypeEnum.string,
connected: true,
showTargetInApp: false,
showTargetInPlugin: false
};
}
const pluginInput = modules.find((module) => module.flowType === FlowNodeTypeEnum.pluginInput); const pluginInput = modules.find((module) => module.flowType === FlowNodeTypeEnum.pluginInput);
const customOutput = modules.find((module) => module.flowType === FlowNodeTypeEnum.pluginOutput); const pluginOutput = modules.find((module) => module.flowType === FlowNodeTypeEnum.pluginOutput);
return { return {
inputs: pluginInput inputs: pluginInput
? [ ? [
getPluginTemplatePluginIdInput(pluginId), {
// plugin id
key: ModuleInputKeyEnum.pluginId,
type: FlowNodeInputTypeEnum.hidden,
label: 'pluginId',
value: pluginId,
valueType: ModuleIOValueTypeEnum.string,
connected: true,
showTargetInApp: false,
showTargetInPlugin: false
},
// switch
Input_Template_Switch,
...pluginInput.inputs.map((item) => ({ ...pluginInput.inputs.map((item) => ({
...item, ...item,
...getModuleInputUiField(item),
value: getOrInitModuleInputValue(item),
edit: false, edit: false,
connected: false connected: false
})) }))
] ]
: [], : [],
outputs: customOutput outputs: pluginOutput
? customOutput.outputs.map((item) => ({ ? pluginOutput.outputs.map((item) => ({
...item, ...item,
edit: false edit: false
})) }))
......
import { ModuleTemplateTypeEnum } from '../module/constants';
import { ModuleItemType } from '../module/type'; import { ModuleItemType } from '../module/type';
export const defaultModules: ModuleItemType[] = [ export const defaultModules: ModuleItemType[] = [
...@@ -28,13 +27,8 @@ export const defaultModules: ModuleItemType[] = [ ...@@ -28,13 +27,8 @@ export const defaultModules: ModuleItemType[] = [
} }
]; ];
export enum PluginTypeEnum { export enum PluginSourceEnum {
personal = 'personal', personal = 'personal',
community = 'community', community = 'community',
commercial = 'commercial' commercial = 'commercial'
} }
export const PluginType2TemplateTypeMap = {
[PluginTypeEnum.personal]: ModuleTemplateTypeEnum.personalPlugin,
[PluginTypeEnum.community]: ModuleTemplateTypeEnum.communityPlugin,
[PluginTypeEnum.commercial]: ModuleTemplateTypeEnum.commercialPlugin
};
import { ModuleTemplateTypeEnum } from 'core/module/constants'; import { ModuleTemplateTypeEnum } from 'core/module/constants';
import type { ModuleItemType } from '../module/type.d'; import type { FlowModuleTemplateType, ModuleItemType } from '../module/type.d';
import { PluginTypeEnum } from './constants'; import { PluginSourceEnum } from './constants';
export type PluginItemSchema = { export type PluginItemSchema = {
_id: string; _id: string;
...@@ -16,11 +16,12 @@ export type PluginItemSchema = { ...@@ -16,11 +16,12 @@ export type PluginItemSchema = {
/* plugin template */ /* plugin template */
export type PluginTemplateType = { export type PluginTemplateType = {
author?: string;
id: string; id: string;
type: `${PluginTypeEnum}`; source: `${PluginSourceEnum}`;
templateType: FlowModuleTemplateType['templateType'];
name: string; name: string;
avatar: string; avatar: string;
intro: string; intro: string;
modules: ModuleItemType[]; modules: ModuleItemType[];
templateType?: `${ModuleTemplateTypeEnum}`;
}; };
{
"name": "@fastgpt/plugins",
"version": "1.0.0",
"dependencies": {},
"devDependencies": {
"@types/node": "^20.8.5"
}
}
{
"compilerOptions": {
"target": "es2015",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": "."
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts", "../**/*.d.ts"],
"exclude": ["node_modules"]
}
...@@ -10,7 +10,7 @@ export async function createQuestionGuide({ ...@@ -10,7 +10,7 @@ export async function createQuestionGuide({
messages: ChatMessageItemType[]; messages: ChatMessageItemType[];
model: string; model: string;
}) { }) {
const ai = getAIApi(undefined, 48000); const ai = getAIApi(undefined, 480000);
const data = await ai.chat.completions.create({ const data = await ai.chat.completions.create({
model: model, model: model,
temperature: 0, temperature: 0,
......
import { MongoPlugin } from './schema'; import { MongoPlugin } from './schema';
import { FlowModuleTemplateType } from '@fastgpt/global/core/module/type'; import { FlowModuleTemplateType } from '@fastgpt/global/core/module/type';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { formatPluginToPreviewModule } from '@fastgpt/global/core/module/utils'; import { plugin2ModuleIO } from '@fastgpt/global/core/module/utils';
import { PluginType2TemplateTypeMap, PluginTypeEnum } from '@fastgpt/global/core/plugin/constants'; import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
import type { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d'; import type { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
import { ModuleTemplateTypeEnum } from '@fastgpt/global/core/module/constants';
/* /*
plugin id rule: plugin id rule:
...@@ -14,84 +15,71 @@ import type { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d'; ...@@ -14,84 +15,71 @@ import type { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
export async function splitCombinePluginId(id: string) { export async function splitCombinePluginId(id: string) {
const splitRes = id.split('-'); const splitRes = id.split('-');
if (splitRes.length === 1 && id.length === 24) { if (splitRes.length === 1) {
return { return {
type: PluginTypeEnum.personal, source: PluginSourceEnum.personal,
pluginId: id pluginId: id
}; };
} }
const [type, pluginId] = id.split('-') as [`${PluginTypeEnum}`, string]; const [source, pluginId] = id.split('-') as [`${PluginSourceEnum}`, string];
if (!type || !pluginId) return Promise.reject('pluginId not found'); if (!source || !pluginId) return Promise.reject('pluginId not found');
return { type, pluginId: id }; return { source, pluginId: id };
} }
const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> => {
const { source, pluginId } = await splitCombinePluginId(id);
if (source === PluginSourceEnum.community) {
const item = global.communityPlugins?.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),
name: item.name,
avatar: item.avatar,
intro: item.intro,
source: PluginSourceEnum.personal,
modules: item.modules,
templateType: ModuleTemplateTypeEnum.personalPlugin
};
}
return Promise.reject('plugin not found');
};
/* format plugin modules to plugin preview module */ /* format plugin modules to plugin preview module */
export async function getPluginPreviewModule({ export async function getPluginPreviewModule({
id id
}: { }: {
id: string; id: string;
}): Promise<FlowModuleTemplateType> { }): Promise<FlowModuleTemplateType> {
// classify const plugin = await getPluginTemplateById(id);
const { type, pluginId } = await splitCombinePluginId(id);
const plugin = await (async () => {
if (type === PluginTypeEnum.community) {
return global.communityPlugins?.find((plugin) => plugin.id === pluginId);
}
if (type === PluginTypeEnum.personal) {
const item = await MongoPlugin.findById(id);
if (!item) return undefined;
return {
id: String(item._id),
name: item.name,
avatar: item.avatar,
intro: item.intro,
type: PluginTypeEnum.personal,
modules: item.modules
};
}
})();
if (!plugin) return Promise.reject('plugin not found');
return { return {
id: plugin.id, id: plugin.id,
templateType: PluginType2TemplateTypeMap[plugin.type], templateType: plugin.templateType,
flowType: FlowNodeTypeEnum.pluginModule, flowType: FlowNodeTypeEnum.pluginModule,
avatar: plugin.avatar, avatar: plugin.avatar,
name: plugin.name, name: plugin.name,
intro: plugin.intro, intro: plugin.intro,
showStatus: true, showStatus: true,
...formatPluginToPreviewModule(plugin.id, plugin.modules) ...plugin2ModuleIO(plugin.id, plugin.modules)
}; };
} }
/* run plugin time */
export async function getPluginRuntimeById(id: string): Promise<PluginTemplateType> { export async function getPluginRuntimeById(id: string): Promise<PluginTemplateType> {
const { type, pluginId } = await splitCombinePluginId(id); const plugin = await getPluginTemplateById(id);
const plugin = await (async () => {
if (type === PluginTypeEnum.community) {
return global.communityPlugins?.find((plugin) => plugin.id === pluginId);
}
if (type === PluginTypeEnum.personal) {
const item = await MongoPlugin.findById(id);
if (!item) return undefined;
return {
id: String(item._id),
name: item.name,
avatar: item.avatar,
intro: item.intro,
type: PluginTypeEnum.personal,
modules: item.modules
};
}
})();
if (!plugin) return Promise.reject('plugin not found');
return { return {
id: plugin.id, id: plugin.id,
type: plugin.type, source: plugin.source,
templateType: plugin.templateType,
name: plugin.name, name: plugin.name,
avatar: plugin.avatar, avatar: plugin.avatar,
intro: plugin.intro, intro: plugin.intro,
......
...@@ -7,7 +7,7 @@ import { MongoPlugin } from '../../../core/plugin/schema'; ...@@ -7,7 +7,7 @@ import { MongoPlugin } from '../../../core/plugin/schema';
import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin'; import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin';
import { PluginItemSchema } from '@fastgpt/global/core/plugin/type'; import { PluginItemSchema } from '@fastgpt/global/core/plugin/type';
import { splitCombinePluginId } from '../../../core/plugin/controller'; import { splitCombinePluginId } from '../../../core/plugin/controller';
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants'; import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
export async function authPluginCrud({ export async function authPluginCrud({
id, id,
...@@ -66,13 +66,13 @@ export async function authPluginCanUse({ ...@@ -66,13 +66,13 @@ export async function authPluginCanUse({
teamId: string; teamId: string;
tmbId: string; tmbId: string;
}) { }) {
const { type, pluginId } = await splitCombinePluginId(id); const { source, pluginId } = await splitCombinePluginId(id);
if (type === PluginTypeEnum.community) { if (source === PluginSourceEnum.community) {
return true; return true;
} }
if (type === PluginTypeEnum.personal) { if (source === PluginSourceEnum.personal) {
const { role } = await getTeamInfoByTmbId({ tmbId }); const { role } = await getTeamInfoByTmbId({ tmbId });
const plugin = await MongoPlugin.findOne({ _id: pluginId, teamId }); const plugin = await MongoPlugin.findOne({ _id: pluginId, teamId });
if (!plugin) { if (!plugin) {
......
...@@ -74,6 +74,12 @@ importers: ...@@ -74,6 +74,12 @@ importers:
specifier: ^5.0.4 specifier: ^5.0.4
version: registry.npmmirror.com/@types/turndown@5.0.4 version: registry.npmmirror.com/@types/turndown@5.0.4
packages/plugins:
devDependencies:
'@types/node':
specifier: ^20.8.5
version: registry.npmmirror.com/@types/node@20.8.7
packages/service: packages/service:
dependencies: dependencies:
'@fastgpt/global': '@fastgpt/global':
...@@ -161,6 +167,9 @@ importers: ...@@ -161,6 +167,9 @@ importers:
'@fastgpt/global': '@fastgpt/global':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/global version: link:../../packages/global
'@fastgpt/plugins':
specifier: workspace:*
version: link:../../packages/plugins
'@fastgpt/service': '@fastgpt/service':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/service version: link:../../packages/service
......
{ {
"name": "app", "name": "app",
"version": "4.6.4", "version": "4.6.5",
"private": false, "private": false,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
"@chakra-ui/system": "^2.5.8", "@chakra-ui/system": "^2.5.8",
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6", "@emotion/styled": "^11.10.6",
"@fastgpt/plugins": "workspace:*",
"@fastgpt/global": "workspace:*", "@fastgpt/global": "workspace:*",
"@fastgpt/service": "workspace:*", "@fastgpt/service": "workspace:*",
"@fastgpt/web": "workspace:*", "@fastgpt/web": "workspace:*",
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
3. 新增 - 分享链接更多嵌入方式提示,更多DIY方式。 3. 新增 - 分享链接更多嵌入方式提示,更多DIY方式。
4. 优化 - 历史记录模块。弃用旧的历史记录模块,直接在对应地方填写数值即可。 4. 优化 - 历史记录模块。弃用旧的历史记录模块,直接在对应地方填写数值即可。
5. 调整 - 知识库搜索模块 topk 逻辑,采用 MaxToken 计算,兼容不同长度的文本块 5. 调整 - 知识库搜索模块 topk 逻辑,采用 MaxToken 计算,兼容不同长度的文本块
6. 链接读取支持多选择器。参考[Web 站点同步用法](https://doc.fastgpt.in/docs/course/webSync) 6. 链接读取支持多选择器。参考[Web 站点同步用法](https://doc.fastgpt.in/docs/course/websync)
7. [知识库结构详解](https://doc.fastgpt.in/docs/use-cases/datasetengine/) 7. [知识库结构详解](https://doc.fastgpt.in/docs/use-cases/datasetengine/)
8. [知识库提示词详解](https://doc.fastgpt.in/docs/use-cases/ai_settings/#引用模板--引用提示词) 8. [知识库提示词详解](https://doc.fastgpt.in/docs/use-cases/ai_settings/#引用模板--引用提示词)
9. [使用文档](https://doc.fastgpt.in/docs/intro/) 9. [使用文档](https://doc.fastgpt.in/docs/intro/)
......
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1702446643259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4270" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M247.0912 996.1472 100.5568 996.1472c-39.936 0-72.4992-32.5632-72.4992-72.4992L28.0576 81.92c0-39.936 32.5632-72.4992 72.4992-72.4992l766.0544 0c39.936 0 72.4992 32.5632 72.4992 72.4992l0 210.5344c0 12.3904-10.0352 22.528-22.528 22.528s-22.528-10.0352-22.528-22.528L894.0544 81.92c0-15.1552-12.288-27.5456-27.5456-27.5456L100.5568 54.3744c-15.1552 0-27.5456 12.288-27.5456 27.5456L73.0112 923.648c0 15.1552 12.288 27.5456 27.5456 27.5456l146.5344 0c12.3904 0 22.528 10.0352 22.528 22.528S259.4816 996.1472 247.0912 996.1472z" fill="#FF9000" p-id="4271"></path><path d="M745.2672 192.1024 174.6944 192.1024c-12.3904 0-22.528-10.0352-22.528-22.528s10.0352-22.528 22.528-22.528l570.5728 0c12.3904 0 22.528 10.0352 22.528 22.528S757.6576 192.1024 745.2672 192.1024z" fill="#FF9000" p-id="4272"></path><path d="M437.6576 429.6704 174.6944 429.6704c-12.3904 0-22.528-10.0352-22.528-22.528s10.0352-22.528 22.528-22.528l262.9632 0c12.3904 0 22.528 10.0352 22.528 22.528S450.1504 429.6704 437.6576 429.6704z" fill="#FF9000" p-id="4273"></path><path d="M620.6464 310.8864 174.6944 310.8864c-12.3904 0-22.528-10.0352-22.528-22.528s10.0352-22.528 22.528-22.528l445.952 0c12.3904 0 22.528 10.0352 22.528 22.528S633.1392 310.8864 620.6464 310.8864z" fill="#FF9000" p-id="4274"></path><path d="M399.6672 1009.8688c-6.2464 0-12.288-2.56-16.5888-7.2704-5.2224-5.7344-7.168-13.7216-5.12-21.2992l40.8576-146.6368c1.024-3.6864 3.072-7.168 5.7344-9.8304l408.9856-408.9856c14.1312-14.0288 36.9664-14.0288 51.0976 0l97.792 97.792c6.8608 6.8608 10.5472 15.872 10.5472 25.4976s-3.7888 18.7392-10.5472 25.4976L928.8704 618.496c-4.1984 4.1984-9.9328 6.5536-15.872 6.5536s-11.6736-2.3552-15.872-6.5536l-66.048-66.048c-8.8064-8.8064-8.8064-23.04 0-31.8464s23.04-8.8064 31.8464 0l50.176 50.176 31.4368-31.4368L859.136 454.0416 460.6976 852.48 431.104 958.6688 546.7136 936.96l231.7312-231.7312c5.0176-5.4272 50.7904-52.6336 107.2128-56.7296 12.3904-0.9216 23.1424 8.3968 24.064 20.7872 0.9216 12.3904-8.3968 23.1424-20.7872 24.064-40.3456 2.9696-77.4144 42.2912-77.824 42.7008-0.2048 0.2048-0.4096 0.512-0.7168 0.7168L573.5424 973.7216c-3.1744 3.1744-7.2704 5.3248-11.776 6.2464l-158.0032 29.5936C402.432 1009.7664 401.1008 1009.8688 399.6672 1009.8688z" fill="#FF9000" p-id="4275"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1702452532573" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5265" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M28.444444 142.222222v739.555556c0 62.577778 51.2 113.777778 113.777778 113.777778h739.555556c62.577778 0 113.777778-51.2 113.777778-113.777778V142.222222c0-62.577778-51.2-113.777778-113.777778-113.777778H142.222222C79.644444 28.444444 28.444444 79.644444 28.444444 142.222222z m830.577778 773.688889H164.977778c-31.288889 0-56.888889-25.6-56.888889-56.888889V164.977778c0-31.288889 25.6-56.888889 56.888889-56.888889h691.2c31.288889 0 56.888889 25.6 56.888889 56.888889v691.2c2.844444 34.133333-22.755556 59.733333-54.044445 59.733333z" fill="#48C9B0" p-id="5266"></path><path d="M765.155556 756.622222l-8.533334-8.533333-22.755555-22.755556 31.288889-31.288889c17.066667-17.066667 17.066667-39.822222 0-56.888888-17.066667-17.066667-42.666667-17.066667-56.888889 0l-31.288889 31.288888-36.977778-36.977777c-17.066667-17.066667-39.822222-17.066667-56.888889 0-17.066667 17.066667-17.066667 42.666667 0 56.888889l36.977778 36.977777-34.133333 34.133334c-17.066667 17.066667-17.066667 42.666667 0 56.888889 17.066667 17.066667 39.822222 17.066667 56.888888 0l34.133334-34.133334 22.755555 22.755556 8.533334 8.533333c17.066667 17.066667 39.822222 17.066667 56.888889 0s14.222222-42.666667 0-56.888889zM355.555556 426.666667l136.533333-136.533334c17.066667-17.066667 17.066667-42.666667 0-56.888889-17.066667-17.066667-42.666667-17.066667-56.888889 0l-99.555556 99.555556-48.355555-48.355556c-17.066667-17.066667-42.666667-17.066667-56.888889 0-17.066667 17.066667-17.066667 39.822222 0 56.888889l85.333333 85.333334c11.377778 11.377778 28.444444 11.377778 39.822223 0zM753.777778 270.222222c-17.066667-17.066667-42.666667-17.066667-56.888889 0l-426.666667 426.666667c-17.066667 17.066667-17.066667 42.666667 0 56.888889 17.066667 17.066667 42.666667 17.066667 56.888889 0l426.666667-426.666667c17.066667-14.222222 17.066667-39.822222 0-56.888889z" fill="#48C9B0" p-id="5267"></path></svg>
\ No newline at end of file
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
"Chat Logs Tips": "Logs record the app's online, shared, and API(chatId is existing) conversations", "Chat Logs Tips": "Logs record the app's online, shared, and API(chatId is existing) conversations",
"Chat logs": "Chat Logs", "Chat logs": "Chat Logs",
"Confirm Del App Tip": "Confirm to delete the app and all its chats", "Confirm Del App Tip": "Confirm to delete the app and all its chats",
"Confirm Save App Tip": "The application may be in advanced orchestration mode, and the advanced orchestration configuration will be overwritten after saving, please confirm!",
"Connection is invalid": "Connecting is invalid", "Connection is invalid": "Connecting is invalid",
"Connection type is different": "Connection type is different", "Connection type is different": "Connection type is different",
"Copy Module Config": "Copy config", "Copy Module Config": "Copy config",
...@@ -52,7 +51,7 @@ ...@@ -52,7 +51,7 @@
"My Modules": "My Custom Modules", "My Modules": "My Custom Modules",
"No Modules": "No module", "No Modules": "No module",
"System Module": "System Module", "System Module": "System Module",
"type": "{{type}}\n{{example}}" "type": "{{type}}\n{{description}}"
}, },
"modules": { "modules": {
"Title is required": "Title is required" "Title is required": "Title is required"
...@@ -89,32 +88,6 @@ ...@@ -89,32 +88,6 @@
"share": "Share", "share": "Share",
"test": "Test Chat " "test": "Test Chat "
}, },
"response": {
"module cq": "Question classification list",
"module cq result": "Classification Result",
"module extract description": "Extract Description",
"module extract result": "Extract Result",
"module historyPreview": "Messages",
"module http body": "Body",
"module http result": "Response",
"module http url": "Request Url",
"module limit": "Count Limit",
"module maxToken": "MaxTokens",
"module model": "Model",
"module name": "Name",
"module price": "Price",
"module query": "Question/Query",
"module question": "Question",
"module quoteList": "Quotes",
"module runningTime": "Time",
"module search query": "Query",
"module search response": "Search Result",
"module similarity": "Similarity",
"module temperature": "Temperature",
"module time": "Running Time",
"module tokens": "Tokens",
"plugin output": "Plugin Output"
},
"retry": "Retry" "retry": "Retry"
}, },
"common": { "common": {
...@@ -239,6 +212,11 @@ ...@@ -239,6 +212,11 @@
"system": { "system": {
"Help Chatbot": "Chatbot Helper", "Help Chatbot": "Chatbot Helper",
"Use Helper": "UsingHelp" "Use Helper": "UsingHelp"
},
"ui": {
"textarea": {
"Magnifying": "Magnifying"
}
} }
}, },
"core": { "core": {
...@@ -262,6 +240,13 @@ ...@@ -262,6 +240,13 @@
"TTS Tip": "After this function is enabled, the voice playback function can be used after each conversation. Use of this feature may incur additional charges.", "TTS Tip": "After this function is enabled, the voice playback function can be used after each conversation. Use of this feature may incur additional charges.",
"Welcome Text": "Welcome Text", "Welcome Text": "Welcome Text",
"create app": "Create App", "create app": "Create App",
"edit": {
"Confirm Save App Tip": "The application may be in advanced orchestration mode, and the advanced orchestration configuration will be overwritten after saving, please confirm!",
"Out Ad Edit": "You are about to exit the Advanced orchestration page, please confirm",
"Prompt Editor": "Prompt Editor",
"Save and out": "Save out",
"UnSave": "UnSave"
},
"logs": { "logs": {
"Source And Time": "Source & Time" "Source And Time": "Source & Time"
}, },
...@@ -325,6 +310,34 @@ ...@@ -325,6 +310,34 @@
"Read Quote": "Read Quote", "Read Quote": "Read Quote",
"Read Source": "Read Source" "Read Source": "Read Source"
}, },
"response": {
"context total length": "Context Length",
"module cq": "Question classification list",
"module cq result": "Classification Result",
"module extract description": "Extract Description",
"module extract result": "Extract Result",
"module historyPreview": "Messages",
"module http body": "Body",
"module http result": "Response",
"module http url": "Request Url",
"module limit": "Count Limit",
"module maxToken": "MaxTokens",
"module model": "Model",
"module name": "Name",
"module price": "Price",
"module query": "Question/Query",
"module question": "Question",
"module quoteList": "Quotes",
"module runningTime": "Time",
"module search query": "Query",
"module search response": "Search Result",
"module similarity": "Similarity",
"module temperature": "Temperature",
"module time": "Running Time",
"module tokens": "Tokens",
"plugin output": "Plugin Output",
"text output": "Text Output"
},
"tts": { "tts": {
"Stop Speech": "Stop" "Stop Speech": "Stop"
} }
...@@ -506,14 +519,42 @@ ...@@ -506,14 +519,42 @@
"Plugin output must connect": "Custom outputs must all be connected", "Plugin output must connect": "Custom outputs must all be connected",
"Variable": "Variable", "Variable": "Variable",
"Variable Setting": "Variable Setting", "Variable Setting": "Variable Setting",
"edit": {
"Field Already Exist": "Key already exist",
"Field Edit": "Field Edit"
},
"extract": {
"Enum Description": "Lists the possible values for the field, one per row",
"Enum Value": "Enum",
"Field Description Placeholder": "Name/age /sql statement......",
"Field Setting Title": "Extract field configuration"
},
"input": { "input": {
"Add Input": "Add Input",
"Input Number": "Input: {{length}}",
"description": {
"Http Request Header": "",
"Http Request Url": "",
"TFSwitch textarea": "",
"anyInput": "",
"dynamic input": "",
"textEditor textarea": "The passed variable can be referenced by {{key}}."
},
"label": { "label": {
"chat history": "", "Http Request Header": "",
"switch": "", "Http Request Method": "",
"user question": "" "Http Request Url": "",
"TFSwitch textarea": "",
"anyInput": "",
"chat history": "chat history",
"switch": "Switch",
"textEditor textarea": "Text Edit",
"user question": "User question"
} }
}, },
"inputType": { "inputType": {
"chat history": "History",
"dynamicTargetInput": "dynamic Target Input",
"input": "Input", "input": "Input",
"selectApp": "App Selector", "selectApp": "App Selector",
"selectChatModel": "Select Chat Model", "selectChatModel": "Select Chat Model",
...@@ -523,18 +564,34 @@ ...@@ -523,18 +564,34 @@
"textarea": "Textarea" "textarea": "Textarea"
}, },
"output": { "output": {
"Add Output": "Add Output",
"Output Number": "Output: {{length}}",
"description": { "description": {
"running done": "running done" "running done": "Triggered when the module call ends"
}, },
"label": { "label": {
"running done": "running done" "result false": "",
"result true": "",
"running done": "End of module call ",
"text": "Text output"
} }
}, },
"template": {
"TFSwitch": "",
"TFSwitch intro": "",
"UnKnow Module": "UnKnow Module",
"textEditor": "Text Editor",
"textEditor intro": "Output of fixed or incoming text after edit"
},
"textEditor": {
"Text Edit": "Text Edit"
},
"valueType": { "valueType": {
"any": "Any", "any": "Any",
"boolean": "Boolean", "boolean": "Boolean",
"chatHistory": "History", "chatHistory": "History",
"datasetQuote": "Dataset Quote", "datasetQuote": "Dataset Quote",
"dynamicTargetInput": "Dynamic Input",
"number": "Number", "number": "Number",
"selectApp": "Select App", "selectApp": "Select App",
"selectDataset": "Select Dataset", "selectDataset": "Select Dataset",
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
"Chat Logs Tips": "日志会记录该应用的在线、分享和 API(需填写 chatId) 对话记录", "Chat Logs Tips": "日志会记录该应用的在线、分享和 API(需填写 chatId) 对话记录",
"Chat logs": "对话日志", "Chat logs": "对话日志",
"Confirm Del App Tip": "确认删除该应用及其所有聊天记录?", "Confirm Del App Tip": "确认删除该应用及其所有聊天记录?",
"Confirm Save App Tip": "该应用可能为高级编排模式,保存后将会覆盖高级编排配置,请确认!",
"Connection is invalid": "连接无效", "Connection is invalid": "连接无效",
"Connection type is different": "连接的类型不一致", "Connection type is different": "连接的类型不一致",
"Copy Module Config": "复制配置", "Copy Module Config": "复制配置",
...@@ -52,7 +51,7 @@ ...@@ -52,7 +51,7 @@
"My Modules": "", "My Modules": "",
"No Modules": "还没有模块~", "No Modules": "还没有模块~",
"System Module": "系统模块", "System Module": "系统模块",
"type": "\"{{type}}\"类型\n{{example}}" "type": "\"{{type}}\"类型\n{{description}}"
}, },
"modules": { "modules": {
"Title is required": "模块名不能为空" "Title is required": "模块名不能为空"
...@@ -89,32 +88,6 @@ ...@@ -89,32 +88,6 @@
"share": "外部链接调用", "share": "外部链接调用",
"test": "测试" "test": "测试"
}, },
"response": {
"module cq": "问题分类列表",
"module cq result": "分类结果",
"module extract description": "提取要求描述",
"module extract result": "提取结果",
"module historyPreview": "完整记录",
"module http body": "请求体",
"module http result": "响应体",
"module http url": "请求地址",
"module limit": "单次搜索上限",
"module maxToken": "最大 Tokens",
"module model": "模型",
"module name": "模型名",
"module price": "计费",
"module query": "问题/检索词",
"module question": "问题",
"module quoteList": "引用内容",
"module runningTime": "运行时长",
"module search query": "检索词",
"module search response": "搜索结果",
"module similarity": "相似度",
"module temperature": "温度",
"module time": "运行时长",
"module tokens": "Tokens",
"plugin output": "插件输出值"
},
"retry": "重新生成" "retry": "重新生成"
}, },
"common": { "common": {
...@@ -239,6 +212,11 @@ ...@@ -239,6 +212,11 @@
"system": { "system": {
"Help Chatbot": "机器人助手", "Help Chatbot": "机器人助手",
"Use Helper": "使用帮助" "Use Helper": "使用帮助"
},
"ui": {
"textarea": {
"Magnifying": "放大"
}
} }
}, },
"core": { "core": {
...@@ -262,6 +240,13 @@ ...@@ -262,6 +240,13 @@
"TTS Tip": "开启后,每次对话后可使用语音播放功能。使用该功能可能产生额外费用。", "TTS Tip": "开启后,每次对话后可使用语音播放功能。使用该功能可能产生额外费用。",
"Welcome Text": "对话开场白", "Welcome Text": "对话开场白",
"create app": "创建属于你的 AI 应用", "create app": "创建属于你的 AI 应用",
"edit": {
"Confirm Save App Tip": "该应用可能为高级编排模式,保存后将会覆盖高级编排配置,请确认!",
"Out Ad Edit": "您即将退出高级编排页面,请确认",
"Prompt Editor": "提示词编辑",
"Save and out": "保存并退出",
"UnSave": "不保存"
},
"logs": { "logs": {
"Source And Time": "来源 & 时间" "Source And Time": "来源 & 时间"
}, },
...@@ -325,6 +310,34 @@ ...@@ -325,6 +310,34 @@
"Read Quote": "查看引用", "Read Quote": "查看引用",
"Read Source": "查看来源" "Read Source": "查看来源"
}, },
"response": {
"context total length": "上下文总长度",
"module cq": "问题分类列表",
"module cq result": "分类结果",
"module extract description": "提取要求描述",
"module extract result": "提取结果",
"module historyPreview": "完整记录",
"module http body": "请求体",
"module http result": "响应体",
"module http url": "请求地址",
"module limit": "单次搜索上限",
"module maxToken": "最大 Tokens",
"module model": "模型",
"module name": "模型名",
"module price": "计费",
"module query": "问题/检索词",
"module question": "问题",
"module quoteList": "引用内容",
"module runningTime": "运行时长",
"module search query": "检索词",
"module search response": "搜索结果",
"module similarity": "相似度",
"module temperature": "温度",
"module time": "运行时长",
"module tokens": "Tokens",
"plugin output": "插件输出值",
"text output": "文本输出"
},
"tts": { "tts": {
"Stop Speech": "停止" "Stop Speech": "停止"
} }
...@@ -506,14 +519,42 @@ ...@@ -506,14 +519,42 @@
"Plugin output must connect": "自定义输出必须全部连接", "Plugin output must connect": "自定义输出必须全部连接",
"Variable": "参数变量", "Variable": "参数变量",
"Variable Setting": "变量设置", "Variable Setting": "变量设置",
"edit": {
"Field Already Exist": "key 重复",
"Field Edit": "字段编辑"
},
"extract": {
"Enum Description": "列举出该字段可能的值,每行一个",
"Enum Value": "枚举值",
"Field Description Placeholder": "姓名/年龄/sql语句……",
"Field Setting Title": "提取字段配置"
},
"input": { "input": {
"Add Input": "添加入参",
"Input Number": "入参: {{length}}",
"description": {
"Http Request Header": "自定义请求头,请严格填入JSON字符串。\n1. 确保最后一个属性没有逗号\n2. 确保 key 包含双引号\n例如: {\"Authorization\":\"Bearer xxx\"}",
"Http Request Url": "新的HTTP请求地址。如果出现两个“请求地址”,可以删除该模块重新加入,会拉取最新的模块配置。",
"TFSwitch textarea": "允许定义一些字符串来实现 false 匹配,每行一个,支持正则表达式。",
"anyInput": "可传入任意内容",
"dynamic input": "接收用户动态添加的参数,会在运行时将这些参数平铺传入",
"textEditor textarea": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。"
},
"label": { "label": {
"Http Request Header": "请求头",
"Http Request Method": "请求方式",
"Http Request Url": "请求地址",
"TFSwitch textarea": "自定义 False 匹配规则",
"anyInput": "任意内容输入",
"chat history": "聊天记录", "chat history": "聊天记录",
"switch": "触发器", "switch": "触发器",
"textEditor textarea": "文本编辑",
"user question": "用户问题" "user question": "用户问题"
} }
}, },
"inputType": { "inputType": {
"chat history": "历史记录",
"dynamicTargetInput": "动态外部数据",
"input": "输入框", "input": "输入框",
"selectApp": "应用选择", "selectApp": "应用选择",
"selectChatModel": "对话模型选择", "selectChatModel": "对话模型选择",
...@@ -523,18 +564,34 @@ ...@@ -523,18 +564,34 @@
"textarea": "段落输入" "textarea": "段落输入"
}, },
"output": { "output": {
"Add Output": "添加出参",
"Output Number": "出参: {{length}}",
"description": { "description": {
"running done": "模块调用结束时触发" "running done": "模块调用结束时触发"
}, },
"label": { "label": {
"running done": "模块调用结束" "result false": "False",
"result true": "True",
"running done": "模块调用结束",
"text": "文本输出"
} }
}, },
"template": {
"TFSwitch": "判断器",
"TFSwitch intro": "根据传入的内容进行 True False 输出。默认情况下,当传入的内容为 false, undefined, null, 0, none 时,会输出 false。你也可以增加一些自定义的字符串来补充输出 false 的内容。",
"UnKnow Module": "未知模块",
"textEditor": "文本加工",
"textEditor intro": "可对固定或传入的文本进行加工后输出"
},
"textEditor": {
"Text Edit": "文本加工"
},
"valueType": { "valueType": {
"any": "任意", "any": "任意",
"boolean": "布尔", "boolean": "布尔",
"chatHistory": "聊天记录", "chatHistory": "聊天记录",
"datasetQuote": "引用内容", "datasetQuote": "引用内容",
"dynamicTargetInput": "动态字段输入",
"number": "数字", "number": "数字",
"selectApp": "应用选择", "selectApp": "应用选择",
"selectDataset": "知识库选择", "selectDataset": "知识库选择",
......
## 插件类型
xxx.json 文件
```ts
type TemplateType =
| 'userGuide'
| 'systemInput'
| 'tools'
| 'textAnswer'
| 'functionCall'
| 'externalCall'
| 'other';
type pluginType = {
author: string; // 填写作者信息
templateType: FlowModuleTemplateType['templateType'];
name: string;
avatar: string;
intro: string;
modules: 直接从高级编排导出配置复制过来;
};
```
## 额外代码怎么写?
参考 `TFSwitch``TextEditor`,通过 HTTP 模块将数据转到一个接口中实现。提交到社区的插件,务必将所有代码都放置在 FastGPT 仓库中,可以在 `projects/app/src/pages/api/plugins` 下新建一个与**插件文件名相同**的子目录进行接口编辑。
## 需要装包怎么办?
可以在 `packages/plugins` 下创建一个与**插件文件名相同**的子目录进行编写,可在 plugins 目录下安装相关依赖。然后在 FastGPT 主项目的接口中通过 `@fastgpt/plugins/xxx` 引入。
{
"author": "FastGPT Team",
"templateType": "tools",
"name": "core.module.template.TFSwitch",
"avatar": "/imgs/module/tfSwitch.svg",
"intro": "core.module.template.TFSwitch intro",
"modules": [
{
"moduleId": "w90mfp",
"name": "定义插件输入",
"avatar": "/imgs/module/input.png",
"flowType": "pluginInput",
"showStatus": false,
"position": {
"x": 616.4226348688949,
"y": -165.05298493910115
},
"inputs": [
{
"key": "input",
"valueType": "any",
"type": "target",
"label": "core.module.input.label.anyInput",
"required": true,
"edit": true,
"connected": true,
"description": "core.module.input.description.anyInput"
},
{
"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.anyInput",
"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": "定义插件输出",
"avatar": "/imgs/module/output.png",
"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模块",
"avatar": "/imgs/module/http.png",
"flowType": "httpRequest",
"showStatus": true,
"position": {
"x": 1210.560012858087,
"y": -387.62433050951756
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "system_httpMethod",
"type": "select",
"valueType": "string",
"label": "core.module.input.label.Http Request Method",
"value": "POST",
"list": [
{
"label": "GET",
"value": "GET"
},
{
"label": "POST",
"value": "POST"
}
],
"required": true,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "system_httpReqUrl",
"type": "input",
"valueType": "string",
"label": "core.module.input.label.Http Request Url",
"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": "textarea",
"valueType": "string",
"label": "core.module.input.label.Http Request Header",
"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": "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": "source",
"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"
}
]
}
]
}
]
}
{
"author": "FastGPT Team",
"templateType": "tools",
"name": "core.module.template.textEditor",
"avatar": "/imgs/module/textEditor.svg",
"intro": "core.module.template.textEditor intro",
"modules": [
{
"moduleId": "w90mfp",
"name": "定义插件输入",
"avatar": "/imgs/module/input.png",
"flowType": "pluginInput",
"showStatus": false,
"position": {
"x": 616.4226348688949,
"y": -165.05298493910115
},
"inputs": [
{
"key": "textarea",
"valueType": "string",
"label": "core.module.input.label.textEditor textarea",
"type": "textarea",
"required": true,
"description": "core.module.input.description.textEditor textarea",
"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": "core.module.input.label.textEditor textarea",
"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": "定义插件输出",
"avatar": "/imgs/module/output.png",
"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模块",
"avatar": "/imgs/module/http.png",
"flowType": "httpRequest",
"showStatus": true,
"position": {
"x": 1086.8929621216014,
"y": -451.7550009773506
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "system_httpMethod",
"type": "select",
"valueType": "string",
"label": "core.module.input.label.Http Request Method",
"value": "POST",
"list": [
{
"label": "GET",
"value": "GET"
},
{
"label": "POST",
"value": "POST"
}
],
"required": true,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "system_httpReqUrl",
"type": "input",
"valueType": "string",
"label": "core.module.input.label.Http Request Url",
"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": "textarea",
"valueType": "string",
"label": "core.module.input.label.Http Request Header",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "",
"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": "source",
"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"
}
]
}
]
}
]
}
...@@ -21,6 +21,7 @@ function Row({ ...@@ -21,6 +21,7 @@ function Row({
value?: string | number; value?: string | number;
rawDom?: React.ReactNode; rawDom?: React.ReactNode;
}) { }) {
const { t } = useTranslation();
const theme = useTheme(); const theme = useTheme();
const val = value || rawDom; const val = value || rawDom;
const strValue = `${value}`; const strValue = `${value}`;
...@@ -29,7 +30,7 @@ function Row({ ...@@ -29,7 +30,7 @@ function Row({
return val !== undefined && val !== '' && val !== 'undefined' ? ( return val !== undefined && val !== '' && val !== 'undefined' ? (
<Box mb={3}> <Box mb={3}>
<Box fontSize={['sm', 'md']} mb={isCodeBlock ? 0 : 1} flex={'0 0 90px'}> <Box fontSize={['sm', 'md']} mb={isCodeBlock ? 0 : 1} flex={'0 0 90px'}>
{label}: {t(label)}:
</Box> </Box>
<Box <Box
borderRadius={'md'} borderRadius={'md'}
...@@ -69,12 +70,12 @@ const WholeResponseModal = ({ ...@@ -69,12 +70,12 @@ const WholeResponseModal = ({
alt={''} alt={''}
w={['14px', '16px']} w={['14px', '16px']}
/> />
{item.moduleName} {t(item.moduleName)}
</Flex> </Flex>
), ),
id: `${i}` id: `${i}`
})), })),
[response] [response, t]
); );
const [currentTab, setCurrentTab] = useState(`0`); const [currentTab, setCurrentTab] = useState(`0`);
...@@ -103,26 +104,33 @@ const WholeResponseModal = ({ ...@@ -103,26 +104,33 @@ const WholeResponseModal = ({
<Tabs list={list} activeId={currentTab} onChange={setCurrentTab} /> <Tabs list={list} activeId={currentTab} onChange={setCurrentTab} />
</Box> </Box>
<Box py={2} px={4} flex={'1 0 0'} overflow={'auto'}> <Box py={2} px={4} flex={'1 0 0'} overflow={'auto'}>
<Row label={t('chat.response.module name')} value={activeModule?.moduleName} /> <Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName)} />
{activeModule?.price !== undefined && ( {activeModule?.price !== undefined && (
<Row <Row
label={t('chat.response.module price')} label={t('core.chat.response.module price')}
value={`¥${formatPrice(activeModule?.price)}`} value={`¥${formatPrice(activeModule?.price)}`}
/> />
)} )}
<Row <Row
label={t('chat.response.module time')} label={t('core.chat.response.module time')}
value={`${activeModule?.runningTime || 0}s`} value={`${activeModule?.runningTime || 0}s`}
/> />
<Row label={t('chat.response.module tokens')} value={`${activeModule?.tokens}`} /> <Row label={t('core.chat.response.module tokens')} value={`${activeModule?.tokens}`} />
<Row label={t('chat.response.module model')} value={activeModule?.model} /> <Row label={t('core.chat.response.module model')} value={activeModule?.model} />
<Row label={t('chat.response.module query')} value={activeModule?.query} /> <Row label={t('core.chat.response.module query')} value={activeModule?.query} />
<Row
label={t('core.chat.response.context total length')}
value={activeModule?.contextTotalLen}
/>
{/* ai chat */} {/* ai chat */}
<Row label={t('chat.response.module temperature')} value={activeModule?.temperature} />
<Row label={t('chat.response.module maxToken')} value={activeModule?.maxToken} />
<Row <Row
label={t('chat.response.module historyPreview')} label={t('core.chat.response.module temperature')}
value={activeModule?.temperature}
/>
<Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
<Row
label={t('core.chat.response.module historyPreview')}
rawDom={ rawDom={
activeModule.historyPreview ? ( activeModule.historyPreview ? (
<> <>
...@@ -148,7 +156,7 @@ const WholeResponseModal = ({ ...@@ -148,7 +156,7 @@ const WholeResponseModal = ({
/> />
{activeModule.quoteList && activeModule.quoteList.length > 0 && ( {activeModule.quoteList && activeModule.quoteList.length > 0 && (
<Row <Row
label={t('chat.response.module quoteList')} label={t('core.chat.response.module quoteList')}
value={`~~~json\n${JSON.stringify(activeModule.quoteList, null, 2)}`} value={`~~~json\n${JSON.stringify(activeModule.quoteList, null, 2)}`}
/> />
)} )}
...@@ -161,27 +169,27 @@ const WholeResponseModal = ({ ...@@ -161,27 +169,27 @@ const WholeResponseModal = ({
value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)} value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
/> />
)} )}
<Row label={t('chat.response.module similarity')} value={activeModule?.similarity} /> <Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
<Row label={t('chat.response.module limit')} value={activeModule?.limit} /> <Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
{/* classify question */} {/* classify question */}
<Row <Row
label={t('chat.response.module cq')} label={t('core.chat.response.module cq')}
value={(() => { value={(() => {
if (!activeModule?.cqList) return ''; if (!activeModule?.cqList) return '';
return activeModule.cqList.map((item) => `* ${item.value}`).join('\n'); return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
})()} })()}
/> />
<Row label={t('chat.response.module cq result')} value={activeModule?.cqResult} /> <Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
{/* extract */} {/* extract */}
<Row <Row
label={t('chat.response.module extract description')} label={t('core.chat.response.module extract description')}
value={activeModule?.extractDescription} value={activeModule?.extractDescription}
/> />
{activeModule?.extractResult && ( {activeModule?.extractResult && (
<Row <Row
label={t('chat.response.module extract result')} label={t('core.chat.response.module extract result')}
value={`~~~json\n${JSON.stringify(activeModule?.extractResult, null, 2)}`} value={`~~~json\n${JSON.stringify(activeModule?.extractResult, null, 2)}`}
/> />
)} )}
...@@ -189,13 +197,13 @@ const WholeResponseModal = ({ ...@@ -189,13 +197,13 @@ const WholeResponseModal = ({
{/* http */} {/* http */}
{activeModule?.body && ( {activeModule?.body && (
<Row <Row
label={t('chat.response.module http body')} label={t('core.chat.response.module http body')}
value={`~~~json\n${JSON.stringify(activeModule?.body, null, 2)}`} value={`~~~json\n${JSON.stringify(activeModule?.body, null, 2)}`}
/> />
)} )}
{activeModule?.httpResult && ( {activeModule?.httpResult && (
<Row <Row
label={t('chat.response.module http result')} label={t('core.chat.response.module http result')}
value={`~~~json\n${JSON.stringify(activeModule?.httpResult, null, 2)}`} value={`~~~json\n${JSON.stringify(activeModule?.httpResult, null, 2)}`}
/> />
)} )}
...@@ -203,10 +211,13 @@ const WholeResponseModal = ({ ...@@ -203,10 +211,13 @@ const WholeResponseModal = ({
{/* plugin */} {/* plugin */}
{activeModule?.pluginOutput && ( {activeModule?.pluginOutput && (
<Row <Row
label={t('chat.response.plugin output')} label={t('core.chat.response.plugin output')}
value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`} value={`~~~json\n${JSON.stringify(activeModule?.pluginOutput, null, 2)}`}
/> />
)} )}
{/* text editor */}
<Row label={t('core.chat.response.text output')} value={activeModule?.textOutput} />
</Box> </Box>
</Flex> </Flex>
</MyModal> </MyModal>
......
...@@ -500,7 +500,7 @@ const ChatBox = ( ...@@ -500,7 +500,7 @@ const ChatBox = (
return { return {
bg: colorMap[chatContent.status] || colorMap.loading, bg: colorMap[chatContent.status] || colorMap.loading,
name: chatContent.moduleName || t('common.Loading') name: t(chatContent.moduleName || '') || t('common.Loading')
}; };
}, [chatHistory, isChatting, t]); }, [chatHistory, isChatting, t]);
/* style end */ /* style end */
...@@ -517,7 +517,7 @@ const ChatBox = ( ...@@ -517,7 +517,7 @@ const ChatBox = (
}; };
}, [router.query]); }, [router.query]);
// add guide text listener // add listener
useEffect(() => { useEffect(() => {
const windowMessage = ({ data }: MessageEvent<{ type: 'sendPrompt'; text: string }>) => { const windowMessage = ({ data }: MessageEvent<{ type: 'sendPrompt'; text: string }>) => {
if (data?.type === 'sendPrompt' && data?.text) { if (data?.type === 'sendPrompt' && data?.text) {
...@@ -536,9 +536,9 @@ const ChatBox = ( ...@@ -536,9 +536,9 @@ const ChatBox = (
}); });
return () => { return () => {
window.removeEventListener('message', windowMessage);
eventBus.off(EventNameEnum.sendQuestion); eventBus.off(EventNameEnum.sendQuestion);
eventBus.off(EventNameEnum.editQuestion); eventBus.off(EventNameEnum.editQuestion);
window.removeEventListener('message', windowMessage);
}; };
}, [handleSubmit, resetInputVal, sendPrompt]); }, [handleSubmit, resetInputVal, sendPrompt]);
......
import React, { useMemo, useState } from 'react';
import {
Box,
Button,
ModalBody,
ModalFooter,
Textarea,
TextareaProps,
useDisclosure
} from '@chakra-ui/react';
import MyTooltip from '@/components/MyTooltip';
import { useTranslation } from 'next-i18next';
import MyIcon from '@/components/Icon';
import MyModal from '@/components/MyModal';
type Props = TextareaProps & {
title?: string;
showSetModalModeIcon?: boolean;
// variables: string[];
};
const PromptTextarea = (props: Props) => {
const { t } = useTranslation();
const { title = t('core.app.edit.Prompt Editor'), value, ...childProps } = props;
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Editor {...childProps} value={value} showSetModalModeIcon onSetModalMode={onOpen} />
{isOpen && (
<MyModal iconSrc="/imgs/modal/edit.svg" title={title} isOpen onClose={onClose}>
<ModalBody>
<Editor
{...childProps}
value={value}
minH={'300px'}
maxH={'auto'}
minW={['100%', '512px']}
showSetModalModeIcon={false}
/>
</ModalBody>
<ModalFooter>
<Button onClick={onClose}>{t('common.Confirm')}</Button>
</ModalFooter>
</MyModal>
)}
</>
);
};
export default PromptTextarea;
const Editor = React.memo(function Editor({
showSetModalModeIcon = true,
onSetModalMode,
...props
}: Props & { onSetModalMode?: () => void }) {
const { t } = useTranslation();
return (
<Box h={'100%'} w={'100%'} position={'relative'}>
<Textarea wordBreak={'break-all'} maxW={'100%'} {...props} />
{showSetModalModeIcon && (
<Box
zIndex={1}
position={'absolute'}
bottom={1}
right={2}
cursor={'pointer'}
onClick={onSetModalMode}
>
<MyTooltip label={t('common.ui.textarea.Magnifying')}>
<MyIcon name={'fullScreenLight'} w={'14px'} color={'myGray.600'} />
</MyTooltip>
</Box>
)}
</Box>
);
});
const VariableSelectBlock = React.memo(function VariableSelectBlock({
variables
}: {
variables: string[];
}) {
return <></>;
});
const Placeholder = React.memo(function Placeholder({
placeholder = ''
}: {
placeholder?: string;
}) {
return (
<Box
zIndex={0}
userSelect={'none'}
color={'myGray.400'}
px={3}
py={2}
position={'absolute'}
top={0}
right={0}
bottom={0}
left={0}
fontSize={'sm'}
>
{placeholder}
</Box>
);
});
...@@ -26,6 +26,7 @@ import type { AIChatModuleProps } from '@fastgpt/global/core/module/node/type.d' ...@@ -26,6 +26,7 @@ import type { AIChatModuleProps } from '@fastgpt/global/core/module/node/type.d'
import type { AppSimpleEditConfigTemplateType } from '@fastgpt/global/core/app/type.d'; import type { AppSimpleEditConfigTemplateType } from '@fastgpt/global/core/app/type.d';
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants'; import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
import { getDocPath } from '@/web/common/system/doc'; import { getDocPath } from '@/web/common/system/doc';
import PromptTextarea from '@/components/common/Textarea/PromptTextarea';
const PromptTemplate = dynamic(() => import('@/components/PromptTemplate')); const PromptTemplate = dynamic(() => import('@/components/PromptTemplate'));
...@@ -187,14 +188,18 @@ const AIChatSettingsModal = ({ ...@@ -187,14 +188,18 @@ const AIChatSettingsModal = ({
</Box> </Box>
</Flex> </Flex>
<Textarea <PromptTextarea
rows={6} bg={'myWhite.400'}
placeholder={ rows={8}
t('template.Quote Content Tip', { default: Prompt_QuoteTemplateList[0].value }) || placeholder={t('template.Quote Content Tip', {
'' default: Prompt_QuoteTemplateList[0].value
} })}
borderColor={'myGray.100'} showSetModalModeIcon
{...register(ModuleInputKeyEnum.aiChatQuoteTemplate)} value={getValues(ModuleInputKeyEnum.aiChatQuoteTemplate)}
onChange={(e) => {
setValue(ModuleInputKeyEnum.aiChatQuoteTemplate, e.target.value);
setRefresh(!refresh);
}}
/> />
</Box> </Box>
)} )}
...@@ -209,13 +214,18 @@ const AIChatSettingsModal = ({ ...@@ -209,13 +214,18 @@ const AIChatSettingsModal = ({
<QuestionOutlineIcon display={['none', 'inline']} ml={1} /> <QuestionOutlineIcon display={['none', 'inline']} ml={1} />
</MyTooltip> </MyTooltip>
</Flex> </Flex>
<Textarea <PromptTextarea
bg={'myWhite.400'}
rows={11} rows={11}
placeholder={ placeholder={t('template.Quote Prompt Tip', {
t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value }) || '' default: Prompt_QuotePromptList[0].value
} })}
borderColor={'myGray.100'} showSetModalModeIcon
{...register(ModuleInputKeyEnum.aiChatQuotePrompt)} value={getValues(ModuleInputKeyEnum.aiChatQuotePrompt)}
onChange={(e) => {
setValue(ModuleInputKeyEnum.aiChatQuotePrompt, e.target.value);
setRefresh(!refresh);
}}
/> />
</Box> </Box>
)} )}
......
...@@ -28,8 +28,8 @@ import React, { ...@@ -28,8 +28,8 @@ import React, {
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt'; import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { EDGE_TYPE, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants'; import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { ModuleItemType } from '@fastgpt/global/core/module/type.d'; import { ModuleItemType } from '@fastgpt/global/core/module/type.d';
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus'; import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
...@@ -174,7 +174,7 @@ export const FlowProvider = ({ ...@@ -174,7 +174,7 @@ export const FlowProvider = ({
const source = nodes.find((node) => node.id === connect.source)?.data; const source = nodes.find((node) => node.id === connect.source)?.data;
const sourceType = (() => { const sourceType = (() => {
if (source?.flowType === FlowNodeTypeEnum.classifyQuestion) { if (source?.flowType === FlowNodeTypeEnum.classifyQuestion) {
return ModuleDataTypeEnum.boolean; return ModuleIOValueTypeEnum.string;
} }
if (source?.flowType === FlowNodeTypeEnum.pluginInput) { if (source?.flowType === FlowNodeTypeEnum.pluginInput) {
return source?.inputs.find((input) => input.key === connect.sourceHandle)?.valueType; return source?.inputs.find((input) => input.key === connect.sourceHandle)?.valueType;
...@@ -193,8 +193,8 @@ export const FlowProvider = ({ ...@@ -193,8 +193,8 @@ export const FlowProvider = ({
}); });
} }
if ( if (
sourceType !== ModuleDataTypeEnum.any && sourceType !== ModuleIOValueTypeEnum.any &&
targetType !== ModuleDataTypeEnum.any && targetType !== ModuleIOValueTypeEnum.any &&
sourceType !== targetType sourceType !== targetType
) { ) {
return toast({ return toast({
...@@ -207,8 +207,7 @@ export const FlowProvider = ({ ...@@ -207,8 +207,7 @@ export const FlowProvider = ({
addEdge( addEdge(
{ {
...connect, ...connect,
type: 'buttonedge', type: EDGE_TYPE,
animated: true,
data: { data: {
onDelete: onDelConnect onDelete: onDelConnect
} }
...@@ -228,6 +227,7 @@ export const FlowProvider = ({ ...@@ -228,6 +227,7 @@ export const FlowProvider = ({
[setEdges, setNodes] [setEdges, setNodes]
); );
/* change */
const onChangeNode = useCallback( const onChangeNode = useCallback(
({ moduleId, type, key, value, index }: FlowNodeChangeProps) => { ({ moduleId, type, key, value, index }: FlowNodeChangeProps) => {
setNodes((nodes) => setNodes((nodes) =>
...@@ -434,51 +434,3 @@ export default React.memo(FlowProvider); ...@@ -434,51 +434,3 @@ export default React.memo(FlowProvider);
export const onChangeNode = (e: FlowNodeChangeProps) => { export const onChangeNode = (e: FlowNodeChangeProps) => {
eventBus.emit(EventNameEnum.updaterNode, e); eventBus.emit(EventNameEnum.updaterNode, e);
}; };
export function flowNode2Modules({
nodes,
edges
}: {
nodes: Node<FlowModuleItemType, string | undefined>[];
edges: Edge<any>[];
}) {
const modules: ModuleItemType[] = nodes.map((item) => ({
moduleId: item.data.moduleId,
name: item.data.name,
avatar: item.data.avatar,
flowType: item.data.flowType,
showStatus: item.data.showStatus,
position: item.position,
inputs: item.data.inputs.map((input) => ({
...input,
connected: false
})),
outputs: item.data.outputs.map((item) => ({
...item,
targets: [] as FlowNodeOutputTargetItemType[]
}))
}));
// update inputs and outputs
modules.forEach((module) => {
module.inputs.forEach((input) => {
input.connected = !!edges.find(
(edge) => edge.target === module.moduleId && edge.targetHandle === input.key
);
});
module.outputs.forEach((output) => {
output.targets = edges
.filter(
(edge) =>
edge.source === module.moduleId && edge.sourceHandle === output.key && edge.targetHandle
)
.map((edge) => ({
moduleId: edge.target,
key: edge.targetHandle || ''
}));
});
});
return modules;
}
...@@ -3,13 +3,25 @@ import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react'; ...@@ -3,13 +3,25 @@ import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useFlowProviderStore } from './FlowProvider'; import { useFlowProviderStore, type useFlowProviderStoreType } from './FlowProvider';
const ImportSettings = ({ onClose }: { onClose: () => void }) => { type Props = {
onClose: () => void;
};
const ImportSettings = ({
onClose,
setNodes,
setEdges,
initData
}: Props & {
setNodes: useFlowProviderStoreType['setNodes'];
setEdges: useFlowProviderStoreType['setEdges'];
initData: useFlowProviderStoreType['initData'];
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToast(); const { toast } = useToast();
const [value, setValue] = useState(''); const [value, setValue] = useState('');
const { setNodes, setEdges, initData } = useFlowProviderStore();
return ( return (
<MyModal <MyModal
...@@ -56,4 +68,8 @@ const ImportSettings = ({ onClose }: { onClose: () => void }) => { ...@@ -56,4 +68,8 @@ const ImportSettings = ({ onClose }: { onClose: () => void }) => {
); );
}; };
export default React.memo(ImportSettings); export default React.memo(function (props: Props) {
const { setNodes, setEdges, initData } = useFlowProviderStore();
return <ImportSettings {...props} setNodes={setNodes} setEdges={setEdges} initData={initData} />;
});
...@@ -7,13 +7,12 @@ import type { ...@@ -7,13 +7,12 @@ import type {
import { useViewport, XYPosition } from 'reactflow'; import { useViewport, XYPosition } from 'reactflow';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { useFlowProviderStore } from './FlowProvider'; import { useFlowProviderStore, type useFlowProviderStoreType } from './FlowProvider';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { appModule2FlowNode } from '@/utils/adapt'; import { appModule2FlowNode } from '@/utils/adapt';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import MyIcon from '@/components/Icon';
import EmptyTip from '@/components/EmptyTip'; import EmptyTip from '@/components/EmptyTip';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { getPreviewPluginModule } from '@/web/core/plugin/api'; import { getPreviewPluginModule } from '@/web/core/plugin/api';
...@@ -22,47 +21,32 @@ import { getErrText } from '@fastgpt/global/common/error/utils'; ...@@ -22,47 +21,32 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
import { moduleTemplatesList } from '@/web/core/modules/template/system'; import { moduleTemplatesList } from '@/web/core/modules/template/system';
import { ModuleTemplateTypeEnum } from '@fastgpt/global/core/module/constants'; import { ModuleTemplateTypeEnum } from '@fastgpt/global/core/module/constants';
enum TemplateTypeEnum {
system = 'system',
plugin = 'plugin'
}
export type ModuleTemplateProps = { export type ModuleTemplateProps = {
systemTemplates: FlowModuleTemplateType[]; templates: FlowModuleTemplateType[];
pluginTemplates: FlowModuleTemplateType[];
}; };
const ModuleTemplateList = ({ type ModuleTemplateListProps = ModuleTemplateProps & {
systemTemplates,
pluginTemplates,
isOpen,
onClose
}: ModuleTemplateProps & {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
};
type RenderListProps = {
templates: FlowModuleTemplateType[];
onClose: () => void;
setNodes: useFlowProviderStoreType['setNodes'];
reactFlowWrapper: useFlowProviderStoreType['reactFlowWrapper'];
};
const ModuleTemplateList = ({
templates,
isOpen,
onClose,
setNodes,
reactFlowWrapper
}: ModuleTemplateListProps & {
setNodes: useFlowProviderStoreType['setNodes'];
reactFlowWrapper: useFlowProviderStoreType['reactFlowWrapper'];
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [templateType, setTemplateType] = React.useState(TemplateTypeEnum.system);
const typeList = useMemo(
() => [
{
type: TemplateTypeEnum.system,
label: t('app.module.System Module'),
child: <RenderList templates={systemTemplates} onClose={onClose} />
},
{
type: TemplateTypeEnum.plugin,
label: t('plugin.Plugin Module'),
child: <RenderList templates={pluginTemplates} onClose={onClose} isPlugin />
}
],
[pluginTemplates, onClose, systemTemplates, t]
);
const TemplateItem = useMemo(
() => typeList.find((item) => item.type === templateType)?.child,
[templateType, typeList]
);
return ( return (
<> <>
...@@ -82,6 +66,7 @@ const ModuleTemplateList = ({ ...@@ -82,6 +66,7 @@ const ModuleTemplateList = ({
position={'absolute'} position={'absolute'}
top={'65px'} top={'65px'}
left={0} left={0}
pt={2}
pb={4} pb={4}
h={isOpen ? 'calc(100% - 100px)' : '0'} h={isOpen ? 'calc(100% - 100px)' : '0'}
w={isOpen ? ['100%', '360px'] : '0'} w={isOpen ? ['100%', '360px'] : '0'}
...@@ -92,47 +77,32 @@ const ModuleTemplateList = ({ ...@@ -92,47 +77,32 @@ const ModuleTemplateList = ({
transition={'.2s ease'} transition={'.2s ease'}
userSelect={'none'} userSelect={'none'}
> >
<Flex pt={4} pb={1} px={5} gap={4} alignItems={'center'} fontSize={['md', 'xl']}> <RenderList
{typeList.map((item) => ( templates={templates}
<Box onClose={onClose}
key={item.label} setNodes={setNodes}
borderBottom={'2px solid transparent'} reactFlowWrapper={reactFlowWrapper}
{...(item.type === templateType />
? {
color: 'myBlue.700',
borderBottomColor: 'myBlue.700',
fontWeight: 'bold'
}
: {
cursor: 'pointer',
onClick: () => setTemplateType(item.type)
})}
>
{item.label}
</Box>
))}
</Flex>
{TemplateItem}
</Flex> </Flex>
</> </>
); );
}; };
export default React.memo(ModuleTemplateList); export default React.memo(function (props: ModuleTemplateListProps) {
const { setNodes, reactFlowWrapper } = useFlowProviderStore();
return <ModuleTemplateList {...props} setNodes={setNodes} reactFlowWrapper={reactFlowWrapper} />;
});
const RenderList = React.memo(function RenderList({ const RenderList = React.memo(function RenderList({
templates, templates,
isPlugin = false, onClose,
onClose setNodes,
}: { reactFlowWrapper
templates: FlowModuleTemplateType[]; }: RenderListProps) {
isPlugin?: boolean;
onClose: () => void;
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const { isPc } = useSystemStore(); const { isPc } = useSystemStore();
const { setNodes, reactFlowWrapper } = useFlowProviderStore();
const { x, y, zoom } = useViewport(); const { x, y, zoom } = useViewport();
const { setLoading } = useSystemStore(); const { setLoading } = useSystemStore();
const { toast } = useToast(); const { toast } = useToast();
...@@ -199,9 +169,9 @@ const RenderList = React.memo(function RenderList({ ...@@ -199,9 +169,9 @@ const RenderList = React.memo(function RenderList({
<Box key={item.type}> <Box key={item.type}>
<Flex> <Flex>
<Box fontWeight={'bold'} flex={1}> <Box fontWeight={'bold'} flex={1}>
{item.label} {t(item.label)}
</Box> </Box>
{isPlugin && item.type === ModuleTemplateTypeEnum.personalPlugin && ( {/* {isPlugin && item.type === ModuleTemplateTypeEnum.personalPlugin && (
<Flex <Flex
alignItems={'center'} alignItems={'center'}
_hover={{ textDecoration: 'underline' }} _hover={{ textDecoration: 'underline' }}
...@@ -213,7 +183,7 @@ const RenderList = React.memo(function RenderList({ ...@@ -213,7 +183,7 @@ const RenderList = React.memo(function RenderList({
</Box> </Box>
<MyIcon name={'common/rightArrowLight'} w={'12px'} /> <MyIcon name={'common/rightArrowLight'} w={'12px'} />
</Flex> </Flex>
)} )} */}
</Flex> </Flex>
<> <>
{item.list.map((template) => ( {item.list.map((template) => (
...@@ -248,9 +218,9 @@ const RenderList = React.memo(function RenderList({ ...@@ -248,9 +218,9 @@ const RenderList = React.memo(function RenderList({
borderRadius={'0'} borderRadius={'0'}
/> />
<Box ml={5} flex={'1 0 0'}> <Box ml={5} flex={'1 0 0'}>
<Box color={'black'}>{template.name}</Box> <Box color={'black'}>{t(template.name)}</Box>
<Box className="textEllipsis3" color={'myGray.500'} fontSize={'sm'}> <Box className="textEllipsis3" color={'myGray.500'} fontSize={'sm'}>
{template.intro} {t(template.intro)}
</Box> </Box>
</Box> </Box>
</Flex> </Flex>
......
import React from 'react';
import { useStoreApi, type ConnectionLineComponentProps } from 'reactflow';
const CustomConnection = ({ fromX, fromY, toX, toY }: ConnectionLineComponentProps) => {
const store = useStoreApi();
const { connectionHandleId } = store.getState();
console.log(fromX, fromY, toX, toY, connectionHandleId);
return (
<g>
<path
fill="none"
stroke={connectionHandleId || ''}
strokeWidth={1.5}
d={`M${fromX},${fromY} C ${fromX} ${toY} ${fromX} ${toY} ${toX},${toY}`}
/>
<circle
cx={toX}
cy={toY}
fill="#fff"
r={3}
stroke={connectionHandleId || ''}
strokeWidth={1.5}
/>
</g>
);
};
export default CustomConnection;
import React from 'react'; import React from 'react';
import { BaseEdge, EdgeLabelRenderer, EdgeProps, getBezierPath } from 'reactflow'; import {
SmoothStepEdge,
EdgeLabelRenderer,
EdgeProps,
getSmoothStepPath,
MarkerType
} from 'reactflow';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
const ButtonEdge = ({ const ButtonEdge = (
id, props: EdgeProps<{
sourceX, onDelete: (id: string) => void;
sourceY, }>
targetX, ) => {
targetY, const {
sourcePosition, id,
targetPosition, sourceX,
style = {}, sourceY,
markerEnd, targetX,
data targetY,
}: EdgeProps<{ sourcePosition,
onDelete: (id: string) => void; targetPosition,
}>) => { data,
const [edgePath, labelX, labelY] = getBezierPath({ selected,
style = {}
} = props;
const [edgePath, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
...@@ -26,9 +36,19 @@ const ButtonEdge = ({ ...@@ -26,9 +36,19 @@ const ButtonEdge = ({
targetPosition targetPosition
}); });
const edgeStyle = {
...style,
...(selected
? {
strokeWidth: 4,
stroke: '#3370ff'
}
: { strokeWidth: 2, stroke: '#BDC1C5' })
};
return ( return (
<> <>
<BaseEdge path={edgePath} markerEnd={markerEnd} style={style} /> <SmoothStepEdge {...props} style={edgeStyle} />
<EdgeLabelRenderer> <EdgeLabelRenderer>
<Flex <Flex
alignItems={'center'} alignItems={'center'}
...@@ -48,7 +68,11 @@ const ButtonEdge = ({ ...@@ -48,7 +68,11 @@ const ButtonEdge = ({
}} }}
onClick={() => data?.onDelete(id)} onClick={() => data?.onDelete(id)}
> >
<MyIcon name="closeSolid" w={'100%'} color={'myGray.600'}></MyIcon> <MyIcon
name="closeSolid"
w={'100%'}
color={selected ? 'myBlue.800' : 'myGray.500'}
></MyIcon>
</Flex> </Flex>
</EdgeLabelRenderer> </EdgeLabelRenderer>
</> </>
......
import React, { useMemo, useState } from 'react';
import {
Box,
Button,
ModalFooter,
ModalBody,
Flex,
Switch,
Input,
Textarea
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import MyModal from '@/components/MyModal';
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next';
import MySelect from '@/components/Select';
import { FlowValueTypeMap } from '@/web/core/modules/constants/dataType';
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
export type EditFieldModeType = 'input' | 'output' | 'pluginInput';
export type EditFieldType = {
type?: `${FlowNodeInputTypeEnum}`; // input type
key: string;
label?: string;
valueType?: `${ModuleDataTypeEnum}`;
description?: string;
required?: boolean;
createSign?: boolean;
};
const FieldEditModal = ({
mode,
defaultField,
onClose,
onSubmit
}: {
mode: EditFieldModeType;
defaultField: EditFieldType;
onClose: () => void;
onSubmit: (data: EditFieldType) => void;
}) => {
const { t } = useTranslation();
const inputTypeList = [
{
label: t('core.module.inputType.target'),
value: FlowNodeInputTypeEnum.target,
valueType: ModuleDataTypeEnum.string
},
{
label: t('core.module.inputType.input'),
value: FlowNodeInputTypeEnum.input,
valueType: ModuleDataTypeEnum.string
},
{
label: t('core.module.inputType.textarea'),
value: FlowNodeInputTypeEnum.textarea,
valueType: ModuleDataTypeEnum.string
},
{
label: t('core.module.inputType.switch'),
value: FlowNodeInputTypeEnum.switch,
valueType: ModuleDataTypeEnum.boolean
},
{
label: t('core.module.inputType.selectDataset'),
value: FlowNodeInputTypeEnum.selectDataset,
valueType: ModuleDataTypeEnum.selectDataset
}
];
const dataTypeSelectList = Object.values(FlowValueTypeMap)
.slice(0, -2)
.map((item) => ({
label: t(item.label),
value: item.value
}));
const { register, getValues, setValue, handleSubmit } = useForm<EditFieldType>({
defaultValues: defaultField
});
const [refresh, setRefresh] = useState(false);
const title = ['input', 'pluginInput'].includes(mode)
? t('app.Input Field Settings')
: t('app.Output Field Settings');
const showValueTypeSelect = useMemo(() => {
return getValues('type') === FlowNodeInputTypeEnum.target || mode === 'output';
}, [getValues, mode, refresh]);
return (
<MyModal isOpen={true} iconSrc="/imgs/module/extract.png" title={title} onClose={onClose}>
<ModalBody minH={'260px'} overflow={'visible'}>
{/* input type select: target, input, textarea.... */}
{mode === 'pluginInput' && (
<Flex alignItems={'center'} mb={5}>
<Box flex={'0 0 70px'}>{t('core.module.Input Type')}</Box>
<MySelect
w={'288px'}
list={inputTypeList}
value={getValues('type')}
onchange={(e: string) => {
const type = e as `${FlowNodeInputTypeEnum}`;
const selectedItem = inputTypeList.find((item) => item.value === type);
setValue('type', type);
setValue('valueType', selectedItem?.valueType);
if (type === FlowNodeInputTypeEnum.selectDataset) {
setValue('label', selectedItem?.label);
}
setRefresh(!refresh);
}}
/>
</Flex>
)}
{['input', 'pluginInput'].includes(mode) && (
<Flex alignItems={'center'} mb={5}>
<Box flex={'0 0 70px'}>{t('common.Require Input')}</Box>
<Switch {...register('required')} />
</Flex>
)}
{showValueTypeSelect && (
<Flex mb={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>{t('core.module.Data Type')}</Box>
<MySelect
w={'288px'}
list={dataTypeSelectList}
value={getValues('valueType')}
onchange={(e: string) => {
const type = e as `${ModuleDataTypeEnum}`;
setValue('valueType', type);
if (
type === ModuleDataTypeEnum.chatHistory ||
type === ModuleDataTypeEnum.datasetQuote
) {
const label = dataTypeSelectList.find((item) => item.value === type)?.label;
setValue('label', label);
}
setRefresh(!refresh);
}}
/>
</Flex>
)}
<Flex mb={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>{t('core.module.Field Name')}</Box>
<Input
placeholder="预约字段/sql语句……"
{...register('label', { required: '字段名不能为空' })}
/>
</Flex>
<Flex mb={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>{t('core.module.Field key')}</Box>
<Input
placeholder="appointment/sql"
{...register('key', { required: '字段 key 不能为空' })}
/>
</Flex>
<Flex mb={5} alignItems={'flex-start'}>
<Box flex={'0 0 70px'}>{t('core.module.Field Description')}</Box>
<Textarea placeholder="可选" rows={3} {...register('description')} />
</Flex>
</ModalBody>
<ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}>
{t('common.Close')}
</Button>
<Button onClick={handleSubmit(onSubmit)}>{t('common.Confirm')}</Button>
</ModalFooter>
</MyModal>
);
};
export default React.memo(FieldEditModal);
export const defaultInputField: EditFieldType = {
label: '',
key: '',
description: '',
type: FlowNodeInputTypeEnum.target,
valueType: ModuleDataTypeEnum.string,
required: true,
createSign: true
};
export const defaultOutputField: EditFieldType = {
label: '',
key: '',
description: '',
valueType: ModuleDataTypeEnum.string,
required: true,
createSign: true
};
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Container from '../modules/Container'; import Container from '../modules/Container';
import RenderInput from '../render/RenderInput'; import RenderInput from '../render/RenderInput';
......
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { Box, Button, Flex, Textarea } from '@chakra-ui/react'; import { Box, Button, Flex, Textarea } from '@chakra-ui/react';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Divider from '../modules/Divider'; import Divider from '../modules/Divider';
import Container from '../modules/Container'; import Container from '../modules/Container';
...@@ -11,7 +11,7 @@ import { customAlphabet } from 'nanoid'; ...@@ -11,7 +11,7 @@ import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 4); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 4);
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleDataTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants'; import { ModuleIOValueTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import SourceHandle from '../render/SourceHandle'; import SourceHandle from '../render/SourceHandle';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
...@@ -19,7 +19,7 @@ import { onChangeNode } from '../../FlowProvider'; ...@@ -19,7 +19,7 @@ import { onChangeNode } from '../../FlowProvider';
const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { moduleId, inputs, outputs } = data; const { moduleId, inputs } = data;
return ( return (
<NodeCard minW={'400px'} {...data}> <NodeCard minW={'400px'} {...data}>
...@@ -29,28 +29,57 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -29,28 +29,57 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
moduleId={moduleId} moduleId={moduleId}
flowInputList={inputs} flowInputList={inputs}
CustomComponent={{ CustomComponent={{
[ModuleInputKeyEnum.agents]: ({ [ModuleInputKeyEnum.agents]: ({ key: agentKey, value = [], ...props }) => {
key: agentKey, const agents = value as ClassifyQuestionAgentItemType[];
value: agents = [], return (
...props <Box>
}: { {agents.map((item, i) => (
key: string; <Box key={item.key} mb={4}>
value?: ClassifyQuestionAgentItemType[]; <Flex alignItems={'center'}>
}) => ( <MyTooltip label={t('common.Delete')}>
<Box> <MyIcon
{agents.map((item, i) => ( mt={1}
<Box key={item.key} mb={4}> mr={2}
<Flex alignItems={'center'}> name={'minus'}
<MyTooltip label={t('common.Delete')}> w={'14px'}
<MyIcon cursor={'pointer'}
color={'myGray.600'}
_hover={{ color: 'red.600' }}
onClick={() => {
onChangeNode({
moduleId,
type: 'updateInput',
key: agentKey,
value: {
...props,
key: agentKey,
value: agents.filter((input) => input.key !== item.key)
}
});
onChangeNode({
moduleId,
type: 'delOutput',
key: item.key
});
}}
/>
</MyTooltip>
<Box flex={1}>分类{i + 1}</Box>
</Flex>
<Box position={'relative'}>
<Textarea
rows={2}
mt={1} mt={1}
mr={2} defaultValue={item.value}
name={'minus'} onChange={(e) => {
w={'14px'} const newVal = agents.map((val) =>
cursor={'pointer'} val.key === item.key
color={'myGray.600'} ? {
_hover={{ color: 'red.600' }} ...val,
onClick={() => { value: e.target.value
}
: val
);
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'updateInput', type: 'updateInput',
...@@ -58,80 +87,50 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -58,80 +87,50 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
value: { value: {
...props, ...props,
key: agentKey, key: agentKey,
value: agents.filter((input) => input.key !== item.key) value: newVal
} }
}); });
onChangeNode({
moduleId,
type: 'delOutput',
key: item.key
});
}} }}
/> />
</MyTooltip> <SourceHandle
<Box flex={1}>分类{i + 1}</Box> handleKey={item.key}
</Flex> valueType={ModuleIOValueTypeEnum.string}
<Box position={'relative'}> />
<Textarea </Box>
rows={2}
mt={1}
defaultValue={item.value}
onChange={(e) => {
const newVal = agents.map((val) =>
val.key === item.key
? {
...val,
value: e.target.value
}
: val
);
onChangeNode({
moduleId,
type: 'updateInput',
key: agentKey,
value: {
...props,
key: agentKey,
value: newVal
}
});
}}
/>
<SourceHandle handleKey={item.key} valueType={ModuleDataTypeEnum.string} />
</Box> </Box>
</Box> ))}
))} <Button
<Button onClick={() => {
onClick={() => { const key = nanoid();
const key = nanoid();
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'updateInput', type: 'updateInput',
key: agentKey,
value: {
...props,
key: agentKey, key: agentKey,
value: agents.concat({ value: '', key }) value: {
} ...props,
}); key: agentKey,
value: agents.concat({ value: '', key })
}
});
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'addOutput', type: 'addOutput',
value: { value: {
key, key,
label: '', label: '',
type: FlowNodeOutputTypeEnum.hidden, type: FlowNodeOutputTypeEnum.hidden,
targets: [] targets: []
} }
}); });
}} }}
> >
添加问题类型 添加问题类型
</Button> </Button>
</Box> </Box>
) );
}
}} }}
/> />
</Container> </Container>
......
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => {
......
...@@ -2,34 +2,37 @@ import React, { useMemo, useState } from 'react'; ...@@ -2,34 +2,37 @@ import React, { useMemo, useState } from 'react';
import { import {
Box, Box,
Button, Button,
ModalHeader,
ModalFooter, ModalFooter,
ModalBody, ModalBody,
Flex, Flex,
Switch, Switch,
Input Input,
Textarea
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type'; import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import Avatar from '@/components/Avatar'; import { useTranslation } from 'next-i18next';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
export const defaultField = {
desc: '',
key: '',
required: true,
enum: ''
};
const ExtractFieldModal = ({ const ExtractFieldModal = ({
defaultField = { defaultField,
desc: '',
key: '',
required: true
},
onClose, onClose,
onSubmit onSubmit
}: { }: {
defaultField?: ContextExtractAgentItemType; defaultField: ContextExtractAgentItemType;
onClose: () => void; onClose: () => void;
onSubmit: (data: ContextExtractAgentItemType) => void; onSubmit: (data: ContextExtractAgentItemType) => void;
}) => { }) => {
const { t } = useTranslation();
const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({ const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({
defaultValues: defaultField defaultValues: defaultField
}); });
...@@ -38,35 +41,42 @@ const ExtractFieldModal = ({ ...@@ -38,35 +41,42 @@ const ExtractFieldModal = ({
<MyModal <MyModal
isOpen={true} isOpen={true}
iconSrc="/imgs/module/extract.png" iconSrc="/imgs/module/extract.png"
title={'提取字段配置'} title={t('core.module.extract.Field Setting Title')}
onClose={onClose} onClose={onClose}
> >
<ModalBody> <ModalBody>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<Box flex={'0 0 70px'}>必填</Box> <Box flex={'0 0 70px'}>{t('common.Require Input')}</Box>
<Switch {...register('required')} /> <Switch {...register('required')} />
</Flex> </Flex>
<Flex mt={5} alignItems={'center'}> <Flex mt={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>字段描述</Box> <Box flex={'0 0 70px'}>{t('core.module.Field key')}</Box>
<Input <Input placeholder="name/age/sql" {...register('key', { required: true })} />
placeholder="姓名/年龄/sql语句……"
{...register('desc', { required: '字段描述不能为空' })}
/>
</Flex> </Flex>
<Flex mt={5} alignItems={'center'}> <Flex mt={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>字段 key</Box> <Box flex={'0 0 70px'}>{t('core.module.Field Description')}</Box>
<Input <Input
placeholder="name/age/sql" placeholder={t('core.module.extract.Field Description Placeholder')}
{...register('key', { required: '字段 key 不能为空' })} {...register('desc', { required: true })}
/> />
</Flex> </Flex>
<Box mt={5}>
<Flex alignItems={'center'}>
{t('core.module.extract.Enum Value')}({t('common.choosable')})
<MyTooltip label={t('core.module.extract.Enum Description')} forceShow>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Flex>
<Textarea rows={5} placeholder={'apple\npeach\nwatermelon'} {...register('enum')} />
</Box>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'base'} mr={3} onClick={onClose}>
取消 {t('common.Close')}
</Button> </Button>
<Button onClick={handleSubmit(onSubmit)}>确认</Button> <Button onClick={handleSubmit(onSubmit)}>{t('common.Confirm')}</Button>
</ModalFooter> </ModalFooter>
</MyModal> </MyModal>
); );
......
...@@ -3,25 +3,24 @@ import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@c ...@@ -3,25 +3,24 @@ import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@c
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../../render/NodeCard';
import Container from '../modules/Container'; import Container from '../../modules/Container';
import { AddIcon } from '@chakra-ui/icons'; import { AddIcon } from '@chakra-ui/icons';
import RenderInput from '../render/RenderInput'; import RenderInput from '../../render/RenderInput';
import Divider from '../modules/Divider'; import Divider from '../../modules/Divider';
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type'; import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../../render/RenderOutput';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import ExtractFieldModal from '../modules/ExtractFieldModal'; import ExtractFieldModal, { defaultField } from './ExtractFieldModal';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants'; import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants'; import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { useFlowProviderStore, onChangeNode } from '../../FlowProvider'; import { onChangeNode } from '../../../FlowProvider';
const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
const { inputs, outputs, moduleId } = data; const { inputs, outputs, moduleId } = data;
const { t } = useTranslation(); const { t } = useTranslation();
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>(); const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
const { onDelEdge } = useFlowProviderStore();
return ( return (
<NodeCard minW={'400px'} {...data}> <NodeCard minW={'400px'} {...data}>
...@@ -42,13 +41,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -42,13 +41,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
<Button <Button
variant={'base'} variant={'base'}
leftIcon={<AddIcon fontSize={'10px'} />} leftIcon={<AddIcon fontSize={'10px'} />}
onClick={() => onClick={() => setEditExtractField(defaultField)}
setEditExtractField({
desc: '',
key: '',
required: true
})
}
> >
新增字段 新增字段
</Button> </Button>
...@@ -150,7 +143,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -150,7 +143,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
key: data.key, key: data.key,
label: `提取结果-${data.desc}`, label: `提取结果-${data.desc}`,
description: '无法提取时不会返回', description: '无法提取时不会返回',
valueType: ModuleDataTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.source,
targets: [] targets: []
}; };
......
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Divider from '../modules/Divider'; import Divider from '../modules/Divider';
import Container from '../modules/Container'; import Container from '../modules/Container';
...@@ -13,10 +13,9 @@ import { ...@@ -13,10 +13,9 @@ import {
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/module/node/constant'; } from '@fastgpt/global/core/module/node/constant';
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants'; import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import { onChangeNode } from '../../FlowProvider';
const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
...@@ -25,54 +24,10 @@ const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -25,54 +24,10 @@ const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => {
<NodeCard minW={'350px'} {...data}> <NodeCard minW={'350px'} {...data}>
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}> <Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
<RenderInput moduleId={moduleId} flowInputList={inputs} /> <RenderInput moduleId={moduleId} flowInputList={inputs} />
<Button
variant={'base'}
mt={5}
leftIcon={<SmallAddIcon />}
onClick={() => {
const key = nanoid();
onChangeNode({
moduleId,
type: 'addInput',
key,
value: {
key,
valueType: ModuleDataTypeEnum.string,
type: FlowNodeInputTypeEnum.target,
label: `入参${inputs.length - 1}`,
edit: true
}
});
}}
>
添加入参
</Button>
</Container> </Container>
<Divider text="Output" /> <Divider text="Output" />
<Container> <Container>
<RenderOutput moduleId={moduleId} flowOutputList={outputs} /> <RenderOutput moduleId={moduleId} flowOutputList={outputs} />
<Box textAlign={'right'} mt={5}>
<Button
variant={'base'}
leftIcon={<SmallAddIcon />}
onClick={() => {
onChangeNode({
moduleId,
type: 'addOutput',
value: {
key: nanoid(),
label: `出参${outputs.length}`,
valueType: ModuleDataTypeEnum.string,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: []
}
});
}}
>
添加出参
</Button>
</Box>
</Container> </Container>
</NodeCard> </NodeCard>
); );
......
import React, { useState } from 'react'; import React, { useState } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import { onChangeNode } from '../../FlowProvider'; import { onChangeNode } from '../../FlowProvider';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { Box, Button, Flex } from '@chakra-ui/react'; import { Box, Button, Flex } from '@chakra-ui/react';
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant'; import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/module/node/constant';
import Container from '../modules/Container'; import Container from '../modules/Container';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import SourceHandle from '../render/SourceHandle'; import SourceHandle from '../render/SourceHandle';
import { defaultInputField, type EditFieldType } from '../modules/FieldEditModal'; import type {
import { useToast } from '@/web/common/hooks/useToast'; EditNodeFieldType,
FlowNodeInputItemType,
FlowNodeOutputItemType
} from '@fastgpt/global/core/module/node/type.d';
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next';
const FieldEditModal = dynamic(() => import('../modules/FieldEditModal')); const FieldEditModal = dynamic(() => import('../render/FieldEditModal'));
const defaultCreateField: EditNodeFieldType = {
label: '',
key: '',
description: '',
inputType: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string,
required: true
};
const createEditField = {
key: true,
name: true,
description: true,
required: true,
dataType: true,
inputType: true
};
const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
const { toast } = useToast(); const [createField, setCreateField] = useState<EditNodeFieldType>();
const [editField, setEditField] = useState<EditFieldType>(); const [editField, setEditField] = useState<EditNodeFieldType>();
return ( return (
<NodeCard minW={'300px'} {...data}> <NodeCard minW={'300px'} {...data}>
...@@ -42,10 +68,10 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -42,10 +68,10 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
_hover={{ color: 'myBlue.600' }} _hover={{ color: 'myBlue.600' }}
onClick={() => onClick={() =>
setEditField({ setEditField({
type: item.type, inputType: item.type,
valueType: item.valueType,
key: item.key, key: item.key,
label: item.label, label: item.label,
valueType: item.valueType,
description: item.description, description: item.description,
required: item.required required: item.required
}) })
...@@ -71,14 +97,13 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -71,14 +97,13 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
}); });
}} }}
/> />
{item.description && ( {item.description && (
<MyTooltip label={item.description} forceShow> <MyTooltip label={t(item.description)} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} mr={1} /> <QuestionOutlineIcon display={['none', 'inline']} mr={1} />
</MyTooltip> </MyTooltip>
)} )}
<Box position={'relative'}> <Box position={'relative'}>
{item.label} {t(item.label)}
{item.required && ( {item.required && (
<Box <Box
position={'absolute'} position={'absolute'}
...@@ -99,95 +124,126 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -99,95 +124,126 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
variant={'base'} variant={'base'}
leftIcon={<SmallAddIcon />} leftIcon={<SmallAddIcon />}
onClick={() => { onClick={() => {
setEditField(defaultInputField); setCreateField(defaultCreateField);
}} }}
> >
添加入参 {t('core.module.input.Add Input')}
</Button> </Button>
</Box> </Box>
</Container> </Container>
{!!editField && ( {!!createField && (
<FieldEditModal <FieldEditModal
mode={'pluginInput'} editField={createEditField}
defaultField={createField}
keys={inputs.map((input) => input.key)}
onClose={() => setCreateField(undefined)}
onSubmit={({ data }) => {
onChangeNode({
moduleId,
type: 'addInput',
value: {
key: data.key,
valueType: data.valueType,
label: data.label,
type: data.inputType,
required: data.required,
description: data.description,
edit: true,
editField: createEditField
}
});
onChangeNode({
moduleId,
type: 'addOutput',
value: {
key: data.key,
valueType: data.valueType,
label: data.label,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: []
}
});
setCreateField(undefined);
}}
/>
)}
{!!editField?.key && (
<FieldEditModal
editField={createEditField}
defaultField={editField} defaultField={editField}
keys={[editField.key]}
onClose={() => setEditField(undefined)} onClose={() => setEditField(undefined)}
onSubmit={(e) => { onSubmit={({ data, changeKey }) => {
// create field if (!data.inputType || !data.key || !data.label) return;
if (e.createSign) {
// check key repeat
const memInput = inputs.find((item) => item.key === e.key);
if (memInput) {
return toast({
status: 'warning',
title: '字段key已存在'
});
}
onChangeNode({
moduleId,
type: 'addInput',
value: {
key: e.key,
valueType: e.valueType,
type: e.type,
label: e.label,
required: e.required,
edit: true
}
});
onChangeNode({
moduleId,
type: 'addOutput',
value: {
key: e.key,
valueType: e.valueType,
label: e.label,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: []
}
});
return setEditField(undefined);
}
// check key valid // check key valid
const memInput = inputs.find((item) => item.key === editField.key); const memInput = inputs.find((item) => item.key === editField.key);
const memOutput = outputs.find((item) => item.key === editField.key); const memOutput = outputs.find((item) => item.key === editField.key);
if (!memInput || !memOutput) return setEditField(undefined); if (!memInput || !memOutput) return setEditField(undefined);
const input = {
const newInput: FlowNodeInputItemType = {
...memInput, ...memInput,
...e type: data.inputType,
valueType: data.valueType,
key: data.key,
required: data.required,
label: data.label,
description: data.description,
...(data.inputType === FlowNodeInputTypeEnum.addInputParam
? {
editField: {
key: true,
name: true,
description: true,
required: true,
dataType: true,
inputType: false
},
defaultEditField: {
label: '',
key: '',
description: '',
inputType: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string,
required: true
}
}
: {})
}; };
const output = { const newOutput: FlowNodeOutputItemType = {
...memOutput, ...memOutput,
...e valueType: data.valueType,
key: data.key,
label: data.label
}; };
// not update key
if (editField.key === e.key) { if (changeKey) {
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'updateInput', type: 'replaceInput',
key: editField.key, key: editField.key,
value: input value: newInput
}); });
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'updateOutput', type: 'replaceOutput',
key: editField.key, key: editField.key,
value: output value: newOutput
}); });
} else { } else {
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'replaceInput', type: 'updateInput',
key: editField.key, key: newInput.key,
value: input value: newInput
}); });
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'replaceOutput', type: 'updateOutput',
key: editField.key, key: newOutput.key,
value: output value: newOutput
}); });
} }
......
import React, { useState } from 'react'; import React, { useState } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import { onChangeNode } from '../../FlowProvider'; import { onChangeNode } from '../../FlowProvider';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { Box, Button, Flex } from '@chakra-ui/react'; import { Box, Button, Flex } from '@chakra-ui/react';
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant'; import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/module/node/constant';
import Container from '../modules/Container'; import Container from '../modules/Container';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { EditFieldType, defaultOutputField } from '../modules/FieldEditModal';
import TargetHandle from '../render/TargetHandle'; import TargetHandle from '../render/TargetHandle';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import {
EditNodeFieldType,
FlowNodeInputItemType,
FlowNodeOutputItemType
} from '@fastgpt/global/core/module/node/type';
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next';
const FieldEditModal = dynamic(() => import('../modules/FieldEditModal')); const FieldEditModal = dynamic(() => import('../render/FieldEditModal'));
const defaultCreateField: EditNodeFieldType = {
label: '',
key: '',
description: '',
inputType: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string,
required: true
};
const createEditField = {
key: true,
name: true,
description: true,
required: false,
dataType: true,
inputType: false
};
const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
const { toast } = useToast(); const [createField, setCreateField] = useState<EditNodeFieldType>();
const [editField, setEditField] = useState<EditFieldType>(); const [editField, setEditField] = useState<EditNodeFieldType>();
return ( return (
<NodeCard minW={'300px'} {...data}> <NodeCard minW={'300px'} {...data}>
...@@ -36,7 +63,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -36,7 +63,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
> >
<TargetHandle handleKey={item.key} valueType={item.valueType} /> <TargetHandle handleKey={item.key} valueType={item.valueType} />
<Box position={'relative'}> <Box position={'relative'}>
{item.label} {t(item.label)}
<Box <Box
position={'absolute'} position={'absolute'}
right={'-6px'} right={'-6px'}
...@@ -47,7 +74,11 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -47,7 +74,11 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
* *
</Box> </Box>
</Box> </Box>
{item.description && (
<MyTooltip label={t(item.description)} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} ml={2} />
</MyTooltip>
)}
<MyIcon <MyIcon
name={'settingLight'} name={'settingLight'}
w={'14px'} w={'14px'}
...@@ -56,10 +87,12 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -56,10 +87,12 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
_hover={{ color: 'myBlue.600' }} _hover={{ color: 'myBlue.600' }}
onClick={() => onClick={() =>
setEditField({ setEditField({
inputType: item.type,
valueType: item.valueType,
key: item.key, key: item.key,
label: item.label, label: item.label,
valueType: item.valueType, description: item.description,
description: item.description required: item.required
}) })
} }
/> />
...@@ -68,7 +101,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -68,7 +101,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
name={'delete'} name={'delete'}
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
ml={3} ml={2}
_hover={{ color: 'red.500' }} _hover={{ color: 'red.500' }}
onClick={() => { onClick={() => {
onChangeNode({ onChangeNode({
...@@ -84,12 +117,6 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -84,12 +117,6 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
}); });
}} }}
/> />
{item.description && (
<MyTooltip label={item.description} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} mr={1} />
</MyTooltip>
)}
</Flex> </Flex>
))} ))}
<Box textAlign={'left'} mt={5}> <Box textAlign={'left'} mt={5}>
...@@ -97,92 +124,106 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -97,92 +124,106 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
variant={'base'} variant={'base'}
leftIcon={<SmallAddIcon />} leftIcon={<SmallAddIcon />}
onClick={() => { onClick={() => {
setEditField(defaultOutputField); setCreateField(defaultCreateField);
}} }}
> >
添加出参 {t('core.module.output.Add Output')}
</Button> </Button>
</Box> </Box>
</Container> </Container>
{!!editField && ( {!!createField && (
<FieldEditModal
editField={createEditField}
defaultField={createField}
keys={inputs.map((input) => input.key)}
onClose={() => setCreateField(undefined)}
onSubmit={({ data }) => {
onChangeNode({
moduleId,
type: 'addInput',
value: {
key: data.key,
valueType: data.valueType,
label: data.label,
type: data.inputType,
required: data.required,
description: data.description,
edit: true,
editField: createEditField
}
});
onChangeNode({
moduleId,
type: 'addOutput',
value: {
key: data.key,
valueType: data.valueType,
label: data.label,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: []
}
});
setCreateField(undefined);
}}
/>
)}
{!!editField?.key && (
<FieldEditModal <FieldEditModal
mode={'output'} editField={createEditField}
defaultField={editField} defaultField={editField}
keys={[editField.key]}
onClose={() => setEditField(undefined)} onClose={() => setEditField(undefined)}
onSubmit={(e) => { onSubmit={({ data, changeKey }) => {
if (e.createSign) { if (!data.inputType || !data.key || !data.label) return;
// check key repeat
const memInput = inputs.find((item) => item.key === e.key);
if (memInput) {
return toast({
status: 'warning',
title: '字段key已存在'
});
}
onChangeNode({ // check key valid
moduleId,
type: 'addInput',
value: {
key: e.key,
valueType: e.valueType,
type: e.type,
label: e.label,
required: e.required,
edit: true
}
});
onChangeNode({
moduleId,
type: 'addOutput',
value: {
key: e.key,
valueType: e.valueType,
label: e.label,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: []
}
});
return setEditField(undefined);
}
const memInput = inputs.find((item) => item.key === editField.key); const memInput = inputs.find((item) => item.key === editField.key);
const memOutput = outputs.find((item) => item.key === editField.key); const memOutput = outputs.find((item) => item.key === editField.key);
if (!memInput || !memOutput) return;
const input = { if (!memInput || !memOutput) return setEditField(undefined);
const newInput: FlowNodeInputItemType = {
...memInput, ...memInput,
...e type: data.inputType,
valueType: data.valueType,
key: data.key,
required: data.required,
label: data.label,
description: data.description
}; };
const output = { const newOutput: FlowNodeOutputItemType = {
...memOutput, ...memOutput,
...e valueType: data.valueType,
key: data.key,
label: data.label
}; };
// not update key
if (editField.key === e.key) { if (changeKey) {
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'updateInput', type: 'replaceInput',
key: editField.key, key: editField.key,
value: input value: newInput
}); });
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'updateOutput', type: 'replaceOutput',
key: editField.key, key: editField.key,
value: output value: newOutput
}); });
} else { } else {
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'replaceInput', type: 'updateInput',
key: editField.key, key: newInput.key,
value: input value: newInput
}); });
onChangeNode({ onChangeNode({
moduleId, moduleId,
type: 'replaceOutput', type: 'updateOutput',
key: editField.key, key: newOutput.key,
value: output value: newOutput
}); });
} }
......
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Container from '../modules/Container'; import Container from '../modules/Container';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => { const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data; const { moduleId, outputs } = data;
return ( return (
<NodeCard minW={'240px'} {...data}> <NodeCard minW={'240px'} {...data}>
......
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Divider from '../modules/Divider'; import Divider from '../modules/Divider';
import Container from '../modules/Container'; import Container from '../modules/Container';
......
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Divider from '../modules/Divider'; import Divider from '../modules/Divider';
import Container from '../modules/Container'; import Container from '../modules/Container';
......
...@@ -24,7 +24,7 @@ import VariableEdit from '../modules/VariableEdit'; ...@@ -24,7 +24,7 @@ import VariableEdit from '../modules/VariableEdit';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import Container from '../modules/Container'; import Container from '../modules/Container';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../render/NodeCard';
import type { VariableItemType } from '@fastgpt/global/core/module/type.d'; import type { VariableItemType } from '@fastgpt/global/core/module/type.d';
import QGSwitch from '@/components/core/module/Flow/components/modules/QGSwitch'; import QGSwitch from '@/components/core/module/Flow/components/modules/QGSwitch';
import TTSSelect from '@/components/core/module/Flow/components/modules/TTSSelect'; import TTSSelect from '@/components/core/module/Flow/components/modules/TTSSelect';
......
...@@ -3,7 +3,7 @@ import React, { useCallback, useMemo, useState } from 'react'; ...@@ -3,7 +3,7 @@ import React, { useCallback, useMemo, useState } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react'; import { Box, Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react';
import { AddIcon } from '@chakra-ui/icons'; import { AddIcon } from '@chakra-ui/icons';
import NodeCard from '../../modules/NodeCard'; import NodeCard from '../../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Container from '../../modules/Container'; import Container from '../../modules/Container';
import { VariableInputEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants'; import { VariableInputEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
......
import React, { useEffect, useMemo, useState } from 'react';
import {
Box,
Button,
ModalFooter,
ModalBody,
Flex,
Switch,
Input,
Textarea
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import MyModal from '@/components/MyModal';
import { DYNAMIC_INPUT_KEY, ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next';
import MySelect from '@/components/Select';
import { FlowValueTypeMap } from '@/web/core/modules/constants/dataType';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/module/node/constant';
import { EditInputFieldMap, EditNodeFieldType } from '@fastgpt/global/core/module/node/type.d';
import { useToast } from '@/web/common/hooks/useToast';
const FieldEditModal = ({
editField = {
key: true,
name: true,
description: true,
dataType: true
},
defaultField,
keys = [],
onClose,
onSubmit
}: {
editField?: EditInputFieldMap;
defaultField: EditNodeFieldType;
keys: string[];
onClose: () => void;
onSubmit: (e: { data: EditNodeFieldType; changeKey: boolean }) => void;
}) => {
const { t } = useTranslation();
const { toast } = useToast();
const isCreate = useMemo(() => !defaultField.key, [defaultField.key]);
const showDynamicInputSelect =
!keys.includes(DYNAMIC_INPUT_KEY) || defaultField.key === DYNAMIC_INPUT_KEY;
const inputTypeList = [
{
label: t('core.module.inputType.target'),
value: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string
},
{
label: t('core.module.inputType.input'),
value: FlowNodeInputTypeEnum.input,
valueType: ModuleIOValueTypeEnum.string
},
{
label: t('core.module.inputType.textarea'),
value: FlowNodeInputTypeEnum.textarea,
valueType: ModuleIOValueTypeEnum.string
},
{
label: t('core.module.inputType.switch'),
value: FlowNodeInputTypeEnum.switch,
valueType: ModuleIOValueTypeEnum.boolean
},
{
label: t('core.module.inputType.selectDataset'),
value: FlowNodeInputTypeEnum.selectDataset,
valueType: ModuleIOValueTypeEnum.selectDataset
},
...(showDynamicInputSelect
? [
{
label: t('core.module.inputType.dynamicTargetInput'),
value: FlowNodeInputTypeEnum.addInputParam,
valueType: ModuleIOValueTypeEnum.any
}
]
: [])
];
const dataTypeSelectList = Object.values(FlowValueTypeMap)
.slice(0, -2)
.map((item) => ({
label: t(item.label),
value: item.value
}));
const { register, getValues, setValue, handleSubmit, watch } = useForm<EditNodeFieldType>({
defaultValues: defaultField
});
const [refresh, setRefresh] = useState(false);
const showDataTypeSelect = useMemo(() => {
if (!editField.dataType) return false;
const inputType = getValues('inputType');
const outputType = getValues('outputType');
if (inputType === FlowNodeInputTypeEnum.target) return true;
if (outputType === FlowNodeOutputTypeEnum.source) return true;
return false;
}, [editField.dataType, getValues, refresh]);
const showRequired = useMemo(() => {
const inputType = getValues('inputType');
const valueType = getValues('valueType');
if (inputType === FlowNodeInputTypeEnum.addInputParam) return false;
return editField.required;
}, [editField.required, getValues, refresh]);
const showNameInput = useMemo(() => {
const inputType = getValues('inputType');
return editField.name;
}, [editField.name, getValues, refresh]);
const showKeyInput = useMemo(() => {
const inputType = getValues('inputType');
const valueType = getValues('valueType');
if (inputType === FlowNodeInputTypeEnum.addInputParam) return false;
return editField.key;
}, [editField.key, getValues, refresh]);
const showDescriptionInput = useMemo(() => {
const inputType = getValues('inputType');
return editField.description;
}, [editField.description, getValues, refresh]);
return (
<MyModal
isOpen={true}
iconSrc="/imgs/module/extract.png"
title={t('core.module.edit.Field Edit')}
onClose={onClose}
>
<ModalBody overflow={'visible'}>
{/* input type select: target, input, textarea.... */}
{editField.inputType && (
<Flex alignItems={'center'} mb={5}>
<Box flex={'0 0 70px'}>{t('core.module.Input Type')}</Box>
<MySelect
w={'288px'}
list={inputTypeList}
value={getValues('inputType')}
onchange={(e: string) => {
const type = e as `${FlowNodeInputTypeEnum}`;
const selectedItem = inputTypeList.find((item) => item.value === type);
setValue('inputType', type);
setValue('valueType', selectedItem?.valueType);
if (type === FlowNodeInputTypeEnum.selectDataset) {
setValue('label', selectedItem?.label);
} else if (type === FlowNodeInputTypeEnum.addInputParam) {
setValue('label', t('core.module.valueType.dynamicTargetInput'));
setValue('key', DYNAMIC_INPUT_KEY);
setValue('required', false);
}
setRefresh(!refresh);
}}
/>
</Flex>
)}
{showRequired && (
<Flex alignItems={'center'} mb={5}>
<Box flex={'0 0 70px'}>{t('common.Require Input')}</Box>
<Switch {...register('required')} />
</Flex>
)}
{showDataTypeSelect && (
<Flex mb={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>{t('core.module.Data Type')}</Box>
<MySelect
w={'288px'}
list={dataTypeSelectList}
value={getValues('valueType')}
onchange={(e: string) => {
const type = e as `${ModuleIOValueTypeEnum}`;
setValue('valueType', type);
if (
type === ModuleIOValueTypeEnum.chatHistory ||
type === ModuleIOValueTypeEnum.datasetQuote
) {
const label = dataTypeSelectList.find((item) => item.value === type)?.label;
setValue('label', label);
}
setRefresh(!refresh);
}}
/>
</Flex>
)}
{showNameInput && (
<Flex mb={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>{t('core.module.Field Name')}</Box>
<Input placeholder="预约字段/sql语句……" {...register('label', { required: true })} />
</Flex>
)}
{showKeyInput && (
<Flex mb={5} alignItems={'center'}>
<Box flex={'0 0 70px'}>{t('core.module.Field key')}</Box>
<Input placeholder="appointment/sql" {...register('key', { required: true })} />
</Flex>
)}
{showDescriptionInput && (
<Flex mb={5} alignItems={'flex-start'}>
<Box flex={'0 0 70px'}>{t('core.module.Field Description')}</Box>
<Textarea placeholder={t('common.choosable')} rows={3} {...register('description')} />
</Flex>
)}
</ModalBody>
<ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}>
{t('common.Close')}
</Button>
<Button
onClick={handleSubmit((data) => {
if (!data.key) return;
if (isCreate && keys.includes(data.key)) {
return toast({
status: 'warning',
title: t('core.module.edit.Field Already Exist')
});
}
onSubmit({
data,
changeKey: !keys.includes(data.key)
});
})}
>
{t('common.Confirm')}
</Button>
</ModalFooter>
</MyModal>
);
};
export default React.memo(FieldEditModal);
...@@ -8,7 +8,11 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons'; ...@@ -8,7 +8,11 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useEditTitle } from '@/web/common/hooks/useEditTitle'; import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useFlowProviderStore, onChangeNode } from '../../FlowProvider'; import {
useFlowProviderStore,
onChangeNode,
type useFlowProviderStoreType
} from '../../FlowProvider';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants'; import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
...@@ -23,20 +27,28 @@ type Props = FlowModuleItemType & { ...@@ -23,20 +27,28 @@ type Props = FlowModuleItemType & {
isPreview?: boolean; isPreview?: boolean;
}; };
const NodeCard = (props: Props) => { const NodeCard = (
props: Props & {
onCopyNode: useFlowProviderStoreType['onCopyNode'];
onResetNode: useFlowProviderStoreType['onResetNode'];
onDelNode: useFlowProviderStoreType['onDelNode'];
}
) => {
const { t } = useTranslation();
const { const {
children, children,
avatar = LOGO_ICON, avatar = LOGO_ICON,
name = '未知模块', name = t('core.module.template.UnKnow Module'),
intro, intro,
minW = '300px', minW = '300px',
moduleId, moduleId,
flowType, flowType,
inputs, inputs,
isPreview isPreview,
onCopyNode,
onResetNode,
onDelNode
} = props; } = props;
const { onCopyNode, onResetNode, onDelNode } = useFlowProviderStore();
const { t } = useTranslation();
const theme = useTheme(); const theme = useTheme();
const { toast } = useToast(); const { toast } = useToast();
const { setLoading } = useSystemStore(); const { setLoading } = useSystemStore();
...@@ -147,10 +159,10 @@ const NodeCard = (props: Props) => { ...@@ -147,10 +159,10 @@ const NodeCard = (props: Props) => {
<Flex className="custom-drag-handle" px={4} py={3} alignItems={'center'}> <Flex className="custom-drag-handle" px={4} py={3} alignItems={'center'}>
<Avatar src={avatar} borderRadius={'md'} objectFit={'contain'} w={'30px'} h={'30px'} /> <Avatar src={avatar} borderRadius={'md'} objectFit={'contain'} w={'30px'} h={'30px'} />
<Box ml={3} fontSize={'lg'} color={'myGray.600'}> <Box ml={3} fontSize={'lg'} color={'myGray.600'}>
{name} {t(name)}
</Box> </Box>
{intro && ( {intro && (
<MyTooltip label={intro} forceShow> <MyTooltip label={t(intro)} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} mb={'1px'} ml={1} /> <QuestionOutlineIcon display={['none', 'inline']} mb={'1px'} ml={1} />
</MyTooltip> </MyTooltip>
)} )}
...@@ -186,4 +198,10 @@ const NodeCard = (props: Props) => { ...@@ -186,4 +198,10 @@ const NodeCard = (props: Props) => {
); );
}; };
export default React.memo(NodeCard); export default React.memo(function (props: Props) {
const { onCopyNode, onResetNode, onDelNode } = useFlowProviderStore();
return (
<NodeCard {...props} onCopyNode={onCopyNode} onResetNode={onResetNode} onDelNode={onDelNode} />
);
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment