V4.6.5-alpha (#609)
This commit is contained in:
parent
dd7b4b98ae
commit
05bf1b2265
@ -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' \
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"uid": "username123",
|
"data": {
|
||||||
|
"uid": "用户唯一凭证"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -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' \
|
|||||||
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 无法更新
|
||||||
|
|||||||
8
packages/global/core/chat/type.d.ts
vendored
8
packages/global/core/chat/type.d.ts
vendored
@ -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 = {
|
|||||||
|
|
||||||
// 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 & {
|
||||||
|
|||||||
13
packages/global/core/module/api.d.ts
vendored
13
packages/global/core/module/api.d.ts
vendored
@ -1,3 +1,16 @@
|
|||||||
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;
|
||||||
|
};
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
textarea = 'textarea',
|
textarea = 'textarea',
|
||||||
select = 'select'
|
select = 'select'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DYNAMIC_INPUT_KEY = 'DYNAMIC_INPUT_KEY';
|
||||||
|
|||||||
@ -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 {
|
|||||||
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';
|
||||||
|
|||||||
66
packages/global/core/module/node/type.d.ts
vendored
66
packages/global/core/module/node/type.d.ts
vendored
@ -1,6 +1,7 @@
|
|||||||
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 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
placeholder?: string; // input,textarea
|
hideInApp?: boolean;
|
||||||
list?: { label: string; value: any }[]; // select
|
hideInPlugin?: boolean;
|
||||||
step?: number; // slider max?: number;
|
|
||||||
max?: number;
|
|
||||||
min?: number;
|
|
||||||
markList?: { label: string; value: any }[]; // slider
|
|
||||||
|
|
||||||
plusField?: boolean; // plus system will show
|
placeholder?: string; // input,textarea
|
||||||
|
|
||||||
|
list?: { label: string; value: any }[]; // select
|
||||||
|
|
||||||
|
markList?: { label: string; value: any }[]; // slider
|
||||||
|
step?: number; // slider
|
||||||
|
max?: number; // slider, number input
|
||||||
|
min?: number; // slider, number input
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FlowNodeOutputTargetItemType = {
|
export type FlowNodeOutputTargetItemType = {
|
||||||
@ -48,15 +56,41 @@ export type FlowNodeOutputTargetItemType = {
|
|||||||
key: string;
|
key: string;
|
||||||
};
|
};
|
||||||
export type FlowNodeOutputItemType = {
|
export type FlowNodeOutputItemType = {
|
||||||
key: `${ModuleOutputKeyEnum}` | string;
|
|
||||||
label?: string;
|
|
||||||
edit?: boolean;
|
|
||||||
description?: string;
|
|
||||||
valueType?: `${ModuleDataTypeEnum}`;
|
|
||||||
type?: `${FlowNodeOutputTypeEnum}`;
|
type?: `${FlowNodeOutputTypeEnum}`;
|
||||||
|
key: `${ModuleOutputKeyEnum}` | string;
|
||||||
|
valueType?: `${ModuleIOValueTypeEnum}`;
|
||||||
|
|
||||||
|
label?: string;
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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
|
||||||
|
};
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
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 {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 {
|
|||||||
} 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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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: []
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
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 = {
|
|||||||
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 {
|
|||||||
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 = {
|
|||||||
类型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 = {
|
|||||||
{
|
{
|
||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 {
|
|||||||
} 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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 = {
|
|||||||
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 {
|
|||||||
} 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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
description:
|
description:
|
||||||
'始终返回数组,如果希望搜索结果为空时执行额外操作,需要用到上面的两个输入以及目标模块的触发器',
|
'始终返回数组,如果希望搜索结果为空时执行额外操作,需要用到上面的两个输入以及目标模块的触发器',
|
||||||
type: FlowNodeOutputTypeEnum.source,
|
type: FlowNodeOutputTypeEnum.source,
|
||||||
valueType: ModuleDataTypeEnum.datasetQuote,
|
valueType: ModuleIOValueTypeEnum.datasetQuote,
|
||||||
targets: []
|
targets: []
|
||||||
},
|
},
|
||||||
Output_Template_Finish
|
Output_Template_Finish
|
||||||
|
|||||||
@ -1,8 +1,16 @@
|
|||||||
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 = {
|
|||||||
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.input,
|
type: FlowNodeInputTypeEnum.select,
|
||||||
valueType: ModuleDataTypeEnum.string,
|
valueType: ModuleIOValueTypeEnum.string,
|
||||||
label: '请求地址',
|
label: 'core.module.input.label.Http Request Method',
|
||||||
description: '请求目标地址',
|
value: 'POST',
|
||||||
placeholder: 'https://api.ai.com/getInventory',
|
list: [
|
||||||
|
{
|
||||||
|
label: 'GET',
|
||||||
|
value: 'GET'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'POST',
|
||||||
|
value: 'POST'
|
||||||
|
}
|
||||||
|
],
|
||||||
required: true,
|
required: true,
|
||||||
showTargetInApp: false,
|
showTargetInApp: false,
|
||||||
showTargetInPlugin: false
|
showTargetInPlugin: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ModuleInputKeyEnum.httpReqUrl,
|
||||||
|
type: FlowNodeInputTypeEnum.input,
|
||||||
|
valueType: ModuleIOValueTypeEnum.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
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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 {
|
|||||||
} 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 = {
|
|||||||
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 = {
|
|||||||
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 = {
|
|||||||
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: []
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
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 = {
|
|||||||
{
|
{
|
||||||
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 {
|
|||||||
} 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 = {
|
|||||||
{
|
{
|
||||||
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 = {
|
|||||||
key: ModuleOutputKeyEnum.userChatInput,
|
key: ModuleOutputKeyEnum.userChatInput,
|
||||||
label: '用户问题',
|
label: '用户问题',
|
||||||
type: FlowNodeOutputTypeEnum.source,
|
type: FlowNodeOutputTypeEnum.source,
|
||||||
valueType: ModuleDataTypeEnum.string,
|
valueType: ModuleIOValueTypeEnum.string,
|
||||||
targets: []
|
targets: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
3
packages/global/core/module/type.d.ts
vendored
3
packages/global/core/module/type.d.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
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 = {
|
|||||||
desc: string;
|
desc: string;
|
||||||
key: string;
|
key: string;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
|
enum?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
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) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
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[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|||||||
9
packages/global/core/plugin/type.d.ts
vendored
9
packages/global/core/plugin/type.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
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 = {
|
|||||||
|
|
||||||
/* 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}`;
|
|
||||||
};
|
};
|
||||||
|
|||||||
8
packages/plugins/package.json
Normal file
8
packages/plugins/package.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "@fastgpt/plugins",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.8.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
packages/plugins/tsconfig.json
Normal file
21
packages/plugins/tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"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({
|
|||||||
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,
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
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';
|
|||||||
|
|
||||||
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';
|
|||||||
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({
|
|||||||
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) {
|
||||||
|
|||||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@ -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:
|
|||||||
'@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
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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 @@
|
|||||||
"@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 @@
|
|||||||
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/)
|
||||||
|
|||||||
1
projects/app/public/imgs/module/textEditor.svg
Normal file
1
projects/app/public/imgs/module/textEditor.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
1
projects/app/public/imgs/module/tfSwitch.svg
Normal file
1
projects/app/public/imgs/module/tfSwitch.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"system": {
|
"system": {
|
||||||
"Help Chatbot": "机器人助手",
|
"Help Chatbot": "机器人助手",
|
||||||
"Use Helper": "使用帮助"
|
"Use Helper": "使用帮助"
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"textarea": {
|
||||||
|
"Magnifying": "放大"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"core": {
|
"core": {
|
||||||
@ -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 @@
|
|||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"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": "知识库选择",
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
## 插件类型
|
||||||
|
|
||||||
|
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` 引入。
|
||||||
334
projects/app/public/pluginTemplates/TFSwitch.json
Normal file
334
projects/app/public/pluginTemplates/TFSwitch.json
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
308
projects/app/public/pluginTemplates/TextEditor.json
Normal file
308
projects/app/public/pluginTemplates/TextEditor.json
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
{
|
||||||
|
"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({
|
|||||||
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({
|
|||||||
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 = ({
|
|||||||
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 = ({
|
|||||||
<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 = ({
|
|||||||
/>
|
/>
|
||||||
{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 = ({
|
|||||||
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 = ({
|
|||||||
{/* 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 = ({
|
|||||||
{/* 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 = (
|
|||||||
|
|
||||||
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 = (
|
|||||||
};
|
};
|
||||||
}, [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 = (
|
|||||||
});
|
});
|
||||||
|
|
||||||
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]);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,113 @@
|
|||||||
|
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'
|
|||||||
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 = ({
|
|||||||
</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 = ({
|
|||||||
<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, {
|
|||||||
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 = ({
|
|||||||
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 = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
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 = ({
|
|||||||
addEdge(
|
addEdge(
|
||||||
{
|
{
|
||||||
...connect,
|
...connect,
|
||||||
type: 'buttonedge',
|
type: EDGE_TYPE,
|
||||||
animated: true,
|
|
||||||
data: {
|
data: {
|
||||||
onDelete: onDelConnect
|
onDelete: onDelConnect
|
||||||
}
|
}
|
||||||
@ -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);
|
|||||||
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';
|
|||||||
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 }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
|||||||
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';
|
|||||||
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[];
|
};
|
||||||
|
|
||||||
|
type ModuleTemplateListProps = ModuleTemplateProps & {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
type RenderListProps = {
|
||||||
|
templates: FlowModuleTemplateType[];
|
||||||
|
onClose: () => void;
|
||||||
|
setNodes: useFlowProviderStoreType['setNodes'];
|
||||||
|
reactFlowWrapper: useFlowProviderStoreType['reactFlowWrapper'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModuleTemplateList = ({
|
const ModuleTemplateList = ({
|
||||||
systemTemplates,
|
templates,
|
||||||
pluginTemplates,
|
|
||||||
isOpen,
|
isOpen,
|
||||||
onClose
|
onClose,
|
||||||
}: ModuleTemplateProps & {
|
setNodes,
|
||||||
isOpen: boolean;
|
reactFlowWrapper
|
||||||
onClose: () => void;
|
}: 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 = ({
|
|||||||
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 = ({
|
|||||||
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({
|
|||||||
<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({
|
|||||||
</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({
|
|||||||
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>
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
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;
|
||||||
@ -1,23 +1,33 @@
|
|||||||
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 = ({
|
|||||||
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 = ({
|
|||||||
}}
|
}}
|
||||||
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>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
ModalHeader,
|
|
||||||
ModalFooter,
|
|
||||||
ModalBody,
|
|
||||||
Flex,
|
|
||||||
Switch,
|
|
||||||
Input
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { customAlphabet } from 'nanoid';
|
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
|
||||||
import MyModal from '@/components/MyModal';
|
|
||||||
import Avatar from '@/components/Avatar';
|
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
|
||||||
|
|
||||||
const ExtractFieldModal = ({
|
|
||||||
defaultField = {
|
|
||||||
desc: '',
|
|
||||||
key: '',
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
onClose,
|
|
||||||
onSubmit
|
|
||||||
}: {
|
|
||||||
defaultField?: ContextExtractAgentItemType;
|
|
||||||
onClose: () => void;
|
|
||||||
onSubmit: (data: ContextExtractAgentItemType) => void;
|
|
||||||
}) => {
|
|
||||||
const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({
|
|
||||||
defaultValues: defaultField
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyModal
|
|
||||||
isOpen={true}
|
|
||||||
iconSrc="/imgs/module/extract.png"
|
|
||||||
title={'提取字段配置'}
|
|
||||||
onClose={onClose}
|
|
||||||
>
|
|
||||||
<ModalBody>
|
|
||||||
<Flex alignItems={'center'}>
|
|
||||||
<Box flex={'0 0 70px'}>必填</Box>
|
|
||||||
<Switch {...register('required')} />
|
|
||||||
</Flex>
|
|
||||||
<Flex mt={5} alignItems={'center'}>
|
|
||||||
<Box flex={'0 0 70px'}>字段描述</Box>
|
|
||||||
<Input
|
|
||||||
placeholder="姓名/年龄/sql语句……"
|
|
||||||
{...register('desc', { required: '字段描述不能为空' })}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
<Flex mt={5} alignItems={'center'}>
|
|
||||||
<Box flex={'0 0 70px'}>字段 key</Box>
|
|
||||||
<Input
|
|
||||||
placeholder="name/age/sql"
|
|
||||||
{...register('key', { required: '字段 key 不能为空' })}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
</ModalBody>
|
|
||||||
|
|
||||||
<ModalFooter>
|
|
||||||
<Button variant={'base'} mr={3} onClick={onClose}>
|
|
||||||
取消
|
|
||||||
</Button>
|
|
||||||
<Button onClick={handleSubmit(onSubmit)}>确认</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
</MyModal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(ExtractFieldModal);
|
|
||||||
@ -1,195 +0,0 @@
|
|||||||
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
|
|
||||||
};
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
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';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
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';
|
|||||||
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';
|
|||||||
|
|
||||||
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>) => {
|
|||||||
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>) => {
|
|||||||
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>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
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>) => {
|
||||||
|
|||||||
@ -0,0 +1,85 @@
|
|||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
ModalFooter,
|
||||||
|
ModalBody,
|
||||||
|
Flex,
|
||||||
|
Switch,
|
||||||
|
Input,
|
||||||
|
Textarea
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import MyModal from '@/components/MyModal';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
|
||||||
|
export const defaultField = {
|
||||||
|
desc: '',
|
||||||
|
key: '',
|
||||||
|
required: true,
|
||||||
|
enum: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExtractFieldModal = ({
|
||||||
|
defaultField,
|
||||||
|
onClose,
|
||||||
|
onSubmit
|
||||||
|
}: {
|
||||||
|
defaultField: ContextExtractAgentItemType;
|
||||||
|
onClose: () => void;
|
||||||
|
onSubmit: (data: ContextExtractAgentItemType) => void;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { register, handleSubmit } = useForm<ContextExtractAgentItemType>({
|
||||||
|
defaultValues: defaultField
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyModal
|
||||||
|
isOpen={true}
|
||||||
|
iconSrc="/imgs/module/extract.png"
|
||||||
|
title={t('core.module.extract.Field Setting Title')}
|
||||||
|
onClose={onClose}
|
||||||
|
>
|
||||||
|
<ModalBody>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 70px'}>{t('common.Require Input')}</Box>
|
||||||
|
<Switch {...register('required')} />
|
||||||
|
</Flex>
|
||||||
|
<Flex mt={5} alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 70px'}>{t('core.module.Field key')}</Box>
|
||||||
|
<Input placeholder="name/age/sql" {...register('key', { required: true })} />
|
||||||
|
</Flex>
|
||||||
|
<Flex mt={5} alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 70px'}>{t('core.module.Field Description')}</Box>
|
||||||
|
<Input
|
||||||
|
placeholder={t('core.module.extract.Field Description Placeholder')}
|
||||||
|
{...register('desc', { required: true })}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<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(ExtractFieldModal);
|
||||||
@ -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>) => {
|
|||||||
<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>) => {
|
|||||||
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: []
|
||||||
};
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
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 {
|
|||||||
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>) => {
|
|||||||
<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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,25 +1,51 @@
|
|||||||
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>) => {
|
|||||||
_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>) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{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>) => {
|
|||||||
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={editField}
|
defaultField={createField}
|
||||||
onClose={() => setEditField(undefined)}
|
keys={inputs.map((input) => input.key)}
|
||||||
onSubmit={(e) => {
|
onClose={() => setCreateField(undefined)}
|
||||||
// create field
|
onSubmit={({ data }) => {
|
||||||
if (e.createSign) {
|
onChangeNode({
|
||||||
// check key repeat
|
moduleId,
|
||||||
const memInput = inputs.find((item) => item.key === e.key);
|
type: 'addInput',
|
||||||
if (memInput) {
|
value: {
|
||||||
return toast({
|
key: data.key,
|
||||||
status: 'warning',
|
valueType: data.valueType,
|
||||||
title: '字段key已存在'
|
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}
|
||||||
|
keys={[editField.key]}
|
||||||
|
onClose={() => setEditField(undefined)}
|
||||||
|
onSubmit={({ data, changeKey }) => {
|
||||||
|
if (!data.inputType || !data.key || !data.label) return;
|
||||||
|
|
||||||
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({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: editField.key,
|
|
||||||
value: input
|
|
||||||
});
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateOutput',
|
|
||||||
key: editField.key,
|
|
||||||
value: output
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
moduleId,
|
moduleId,
|
||||||
type: 'replaceInput',
|
type: 'replaceInput',
|
||||||
key: editField.key,
|
key: editField.key,
|
||||||
value: input
|
value: newInput
|
||||||
});
|
});
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
moduleId,
|
moduleId,
|
||||||
type: 'replaceOutput',
|
type: 'replaceOutput',
|
||||||
key: editField.key,
|
key: editField.key,
|
||||||
value: output
|
value: newOutput
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: newInput.key,
|
||||||
|
value: newInput
|
||||||
|
});
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateOutput',
|
||||||
|
key: newOutput.key,
|
||||||
|
value: newOutput
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,52 @@
|
|||||||
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>) => {
|
|||||||
>
|
>
|
||||||
<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>) => {
|
|||||||
*
|
*
|
||||||
</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>) => {
|
|||||||
_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>) => {
|
|||||||
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>) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{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>) => {
|
|||||||
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
|
<FieldEditModal
|
||||||
mode={'output'}
|
editField={createEditField}
|
||||||
defaultField={editField}
|
defaultField={createField}
|
||||||
onClose={() => setEditField(undefined)}
|
keys={inputs.map((input) => input.key)}
|
||||||
onSubmit={(e) => {
|
onClose={() => setCreateField(undefined)}
|
||||||
if (e.createSign) {
|
onSubmit={({ data }) => {
|
||||||
// check key repeat
|
onChangeNode({
|
||||||
const memInput = inputs.find((item) => item.key === e.key);
|
moduleId,
|
||||||
if (memInput) {
|
type: 'addInput',
|
||||||
return toast({
|
value: {
|
||||||
status: 'warning',
|
key: data.key,
|
||||||
title: '字段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}
|
||||||
|
keys={[editField.key]}
|
||||||
|
onClose={() => setEditField(undefined)}
|
||||||
|
onSubmit={({ data, changeKey }) => {
|
||||||
|
if (!data.inputType || !data.key || !data.label) return;
|
||||||
|
|
||||||
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({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: editField.key,
|
|
||||||
value: input
|
|
||||||
});
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateOutput',
|
|
||||||
key: editField.key,
|
|
||||||
value: output
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
moduleId,
|
moduleId,
|
||||||
type: 'replaceInput',
|
type: 'replaceInput',
|
||||||
key: editField.key,
|
key: editField.key,
|
||||||
value: input
|
value: newInput
|
||||||
});
|
});
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
moduleId,
|
moduleId,
|
||||||
type: 'replaceOutput',
|
type: 'replaceOutput',
|
||||||
key: editField.key,
|
key: editField.key,
|
||||||
value: output
|
value: newOutput
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: newInput.key,
|
||||||
|
value: newInput
|
||||||
|
});
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateOutput',
|
||||||
|
key: newOutput.key,
|
||||||
|
value: newOutput
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
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}>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
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';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
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';
|
|||||||
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';
|
|||||||
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';
|
||||||
|
|||||||
@ -0,0 +1,249 @@
|
|||||||
|
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';
|
|||||||
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 & {
|
|||||||
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) => {
|
|||||||
<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) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
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} />
|
||||||
|
);
|
||||||
|
});
|
||||||
@ -1,729 +0,0 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
import type { SelectAppItemType } from '@fastgpt/global/core/module/type';
|
|
||||||
import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Textarea,
|
|
||||||
Input,
|
|
||||||
NumberInput,
|
|
||||||
NumberInputField,
|
|
||||||
NumberInputStepper,
|
|
||||||
NumberIncrementStepper,
|
|
||||||
NumberDecrementStepper,
|
|
||||||
Flex,
|
|
||||||
useDisclosure,
|
|
||||||
Button,
|
|
||||||
useTheme,
|
|
||||||
Grid,
|
|
||||||
Switch
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import { onChangeNode, useFlowProviderStore } from '../../FlowProvider';
|
|
||||||
import Avatar from '@/components/Avatar';
|
|
||||||
import MySelect from '@/components/Select';
|
|
||||||
import MySlider from '@/components/Slider';
|
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
|
||||||
import TargetHandle from './TargetHandle';
|
|
||||||
import MyIcon from '@/components/Icon';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import type { AIChatModuleProps } from '@fastgpt/global/core/module/node/type.d';
|
|
||||||
import { chatModelList, cqModelList } from '@/web/common/system/staticData';
|
|
||||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
|
||||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
|
||||||
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
|
||||||
import type { EditFieldModeType, EditFieldType } from '../modules/FieldEditModal';
|
|
||||||
import { feConfigs } from '@/web/common/system/staticData';
|
|
||||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant';
|
|
||||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
|
||||||
|
|
||||||
const FieldEditModal = dynamic(() => import('../modules/FieldEditModal'));
|
|
||||||
const SelectAppModal = dynamic(() => import('../../SelectAppModal'));
|
|
||||||
const AIChatSettingsModal = dynamic(() => import('../../../AIChatSettingsModal'));
|
|
||||||
const DatasetSelectModal = dynamic(() => import('../../../DatasetSelectModal'));
|
|
||||||
const DatasetParamsModal = dynamic(() => import('../../../DatasetParamsModal'));
|
|
||||||
|
|
||||||
export const Label = React.memo(function Label({
|
|
||||||
moduleId,
|
|
||||||
inputKey,
|
|
||||||
editFiledType = 'input',
|
|
||||||
...item
|
|
||||||
}: FlowNodeInputItemType & {
|
|
||||||
moduleId: string;
|
|
||||||
inputKey: string;
|
|
||||||
editFiledType?: EditFieldModeType;
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { mode } = useFlowProviderStore();
|
|
||||||
const {
|
|
||||||
required = false,
|
|
||||||
description,
|
|
||||||
edit,
|
|
||||||
label,
|
|
||||||
type,
|
|
||||||
valueType,
|
|
||||||
showTargetInApp,
|
|
||||||
showTargetInPlugin
|
|
||||||
} = item;
|
|
||||||
const [editField, setEditField] = useState<EditFieldType>();
|
|
||||||
|
|
||||||
const targetHandle = useMemo(() => {
|
|
||||||
if (type === FlowNodeInputTypeEnum.target) return true;
|
|
||||||
if (mode === 'app' && showTargetInApp) return true;
|
|
||||||
if (mode === 'plugin' && showTargetInPlugin) return true;
|
|
||||||
return false;
|
|
||||||
}, [mode, showTargetInApp, showTargetInPlugin, type]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex className="nodrag" cursor={'default'} alignItems={'center'} position={'relative'}>
|
|
||||||
<Box position={'relative'}>
|
|
||||||
{t(label)}
|
|
||||||
{description && (
|
|
||||||
<MyTooltip label={description} forceShow>
|
|
||||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
|
||||||
</MyTooltip>
|
|
||||||
)}
|
|
||||||
{required && (
|
|
||||||
<Box
|
|
||||||
position={'absolute'}
|
|
||||||
top={'-2px'}
|
|
||||||
right={'-8px'}
|
|
||||||
color={'red.500'}
|
|
||||||
fontWeight={'bold'}
|
|
||||||
>
|
|
||||||
*
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{targetHandle && <TargetHandle handleKey={inputKey} valueType={valueType} />}
|
|
||||||
|
|
||||||
{edit && (
|
|
||||||
<>
|
|
||||||
<MyIcon
|
|
||||||
name={'settingLight'}
|
|
||||||
w={'14px'}
|
|
||||||
cursor={'pointer'}
|
|
||||||
ml={3}
|
|
||||||
_hover={{ color: 'myBlue.600' }}
|
|
||||||
onClick={() =>
|
|
||||||
setEditField({
|
|
||||||
label: item.label,
|
|
||||||
type: item.type,
|
|
||||||
valueType: item.valueType,
|
|
||||||
required: item.required,
|
|
||||||
key: inputKey,
|
|
||||||
description: item.description
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<MyIcon
|
|
||||||
className="delete"
|
|
||||||
name={'delete'}
|
|
||||||
w={'14px'}
|
|
||||||
cursor={'pointer'}
|
|
||||||
ml={2}
|
|
||||||
_hover={{ color: 'red.500' }}
|
|
||||||
onClick={() => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'delInput',
|
|
||||||
key: inputKey,
|
|
||||||
value: ''
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{!!editField && (
|
|
||||||
<FieldEditModal
|
|
||||||
mode={editFiledType}
|
|
||||||
defaultField={editField}
|
|
||||||
onClose={() => setEditField(undefined)}
|
|
||||||
onSubmit={(e) => {
|
|
||||||
const data = {
|
|
||||||
...item,
|
|
||||||
...e
|
|
||||||
};
|
|
||||||
// same key
|
|
||||||
if (editField.key === data.key) {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: data.key,
|
|
||||||
value: data
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// diff key. del and add
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'replaceInput',
|
|
||||||
key: editField.key,
|
|
||||||
value: data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setEditField(undefined);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const RenderInput = ({
|
|
||||||
flowInputList,
|
|
||||||
moduleId,
|
|
||||||
CustomComponent = {},
|
|
||||||
editFiledType
|
|
||||||
}: {
|
|
||||||
flowInputList: FlowNodeInputItemType[];
|
|
||||||
moduleId: string;
|
|
||||||
CustomComponent?: Record<string, (e: FlowNodeInputItemType) => React.ReactNode>;
|
|
||||||
editFiledType?: EditFieldModeType;
|
|
||||||
}) => {
|
|
||||||
const sortInputs = useMemo(
|
|
||||||
() =>
|
|
||||||
flowInputList
|
|
||||||
.filter((item) => !item.plusField || feConfigs.isPlus)
|
|
||||||
.sort((a, b) => (a.key === FlowNodeInputTypeEnum.switch ? -1 : 1)),
|
|
||||||
[flowInputList]
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{sortInputs.map(
|
|
||||||
(item) =>
|
|
||||||
item.type !== FlowNodeInputTypeEnum.hidden && (
|
|
||||||
<Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}>
|
|
||||||
{!!item.label && (
|
|
||||||
<Label
|
|
||||||
editFiledType={editFiledType}
|
|
||||||
moduleId={moduleId}
|
|
||||||
inputKey={item.key}
|
|
||||||
{...item}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Box mt={2} className={'nodrag'}>
|
|
||||||
{item.type === FlowNodeInputTypeEnum.numberInput && (
|
|
||||||
<NumberInputRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.input && (
|
|
||||||
<TextInputRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.switch && (
|
|
||||||
<SwitchRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.textarea && (
|
|
||||||
<TextareaRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.select && (
|
|
||||||
<SelectRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.slider && (
|
|
||||||
<SliderRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.selectApp && (
|
|
||||||
<SelectAppRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.aiSettings && (
|
|
||||||
<AISetting inputs={sortInputs} item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{[
|
|
||||||
FlowNodeInputTypeEnum.selectChatModel,
|
|
||||||
FlowNodeInputTypeEnum.selectCQModel
|
|
||||||
].includes(item.type as any) && (
|
|
||||||
<SelectAIModelRender inputs={sortInputs} item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.selectDataset && (
|
|
||||||
<SelectDatasetRender item={item} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.selectDatasetParamsModal && (
|
|
||||||
<SelectDatasetParamsRender item={item} inputs={sortInputs} moduleId={moduleId} />
|
|
||||||
)}
|
|
||||||
{item.type === FlowNodeInputTypeEnum.custom && CustomComponent[item.key] && (
|
|
||||||
<>{CustomComponent[item.key]({ ...item })}</>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(RenderInput);
|
|
||||||
|
|
||||||
type RenderProps = {
|
|
||||||
inputs?: FlowNodeInputItemType[];
|
|
||||||
item: FlowNodeInputItemType;
|
|
||||||
moduleId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const NumberInputRender = React.memo(function NumberInputRender({ item, moduleId }: RenderProps) {
|
|
||||||
return (
|
|
||||||
<NumberInput
|
|
||||||
defaultValue={item.value}
|
|
||||||
min={item.min}
|
|
||||||
max={item.max}
|
|
||||||
onChange={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: Number(e)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NumberInputField />
|
|
||||||
<NumberInputStepper>
|
|
||||||
<NumberIncrementStepper />
|
|
||||||
<NumberDecrementStepper />
|
|
||||||
</NumberInputStepper>
|
|
||||||
</NumberInput>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const TextInputRender = React.memo(function TextInputRender({ item, moduleId }: RenderProps) {
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
placeholder={item.placeholder}
|
|
||||||
defaultValue={item.value}
|
|
||||||
onBlur={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e.target.value
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SwitchRender = React.memo(function SwitchRender({ item, moduleId }: RenderProps) {
|
|
||||||
return (
|
|
||||||
<Switch
|
|
||||||
size={'lg'}
|
|
||||||
isChecked={item.value}
|
|
||||||
onChange={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e.target.checked
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const TextareaRender = React.memo(function TextareaRender({ item, moduleId }: RenderProps) {
|
|
||||||
return (
|
|
||||||
<Textarea
|
|
||||||
rows={5}
|
|
||||||
placeholder={item.placeholder}
|
|
||||||
resize={'both'}
|
|
||||||
defaultValue={item.value}
|
|
||||||
onBlur={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e.target.value
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SelectRender = React.memo(function SelectRender({ item, moduleId }: RenderProps) {
|
|
||||||
return (
|
|
||||||
<MySelect
|
|
||||||
width={'100%'}
|
|
||||||
value={item.value}
|
|
||||||
list={item.list || []}
|
|
||||||
onchange={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SliderRender = React.memo(function SliderRender({ item, moduleId }: RenderProps) {
|
|
||||||
return (
|
|
||||||
<Box pt={5} pb={4} px={2}>
|
|
||||||
<MySlider
|
|
||||||
markList={item.markList}
|
|
||||||
width={'100%'}
|
|
||||||
min={item.min || 0}
|
|
||||||
max={item.max}
|
|
||||||
step={item.step || 1}
|
|
||||||
value={item.value}
|
|
||||||
onChange={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const AISetting = React.memo(function AISetting({ inputs = [], moduleId }: RenderProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const chatModulesData = useMemo(() => {
|
|
||||||
const obj: Record<string, any> = {};
|
|
||||||
inputs.forEach((item) => {
|
|
||||||
obj[item.key] = item.value;
|
|
||||||
});
|
|
||||||
return obj as AIChatModuleProps;
|
|
||||||
}, [inputs]);
|
|
||||||
|
|
||||||
const {
|
|
||||||
isOpen: isOpenAIChatSetting,
|
|
||||||
onOpen: onOpenAIChatSetting,
|
|
||||||
onClose: onCloseAIChatSetting
|
|
||||||
} = useDisclosure();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
variant={'base'}
|
|
||||||
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
|
|
||||||
onClick={onOpenAIChatSetting}
|
|
||||||
>
|
|
||||||
{t('app.AI Settings')}
|
|
||||||
</Button>
|
|
||||||
{isOpenAIChatSetting && (
|
|
||||||
<AIChatSettingsModal
|
|
||||||
isAdEdit
|
|
||||||
onClose={onCloseAIChatSetting}
|
|
||||||
onSuccess={(e) => {
|
|
||||||
for (let key in e) {
|
|
||||||
const item = inputs.find((input) => input.key === key);
|
|
||||||
if (!item) continue;
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
//@ts-ignore
|
|
||||||
value: e[key]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
onCloseAIChatSetting();
|
|
||||||
}}
|
|
||||||
defaultData={chatModulesData}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SelectAIModelRender = React.memo(function SelectAIModelRender({
|
|
||||||
inputs = [],
|
|
||||||
item,
|
|
||||||
moduleId
|
|
||||||
}: RenderProps) {
|
|
||||||
const modelList = (() => {
|
|
||||||
if (item.type === FlowNodeInputTypeEnum.selectChatModel) return chatModelList;
|
|
||||||
if (item.type === FlowNodeInputTypeEnum.selectCQModel) return cqModelList;
|
|
||||||
return [];
|
|
||||||
})().map((item) => ({
|
|
||||||
model: item.model,
|
|
||||||
name: item.name,
|
|
||||||
maxResponse: item.maxResponse,
|
|
||||||
price: item.price
|
|
||||||
}));
|
|
||||||
|
|
||||||
const onChangeModel = useCallback(
|
|
||||||
(e: string) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: item.key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// update max tokens
|
|
||||||
const model = modelList.find((item) => item.model === e) || modelList[0];
|
|
||||||
if (!model) return;
|
|
||||||
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: 'maxToken',
|
|
||||||
value: {
|
|
||||||
...inputs.find((input) => input.key === 'maxToken'),
|
|
||||||
markList: [
|
|
||||||
{ label: '100', value: 100 },
|
|
||||||
{ label: `${model.maxResponse}`, value: model.maxResponse }
|
|
||||||
],
|
|
||||||
max: model.maxResponse,
|
|
||||||
value: model.maxResponse / 2
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[inputs, item, modelList, moduleId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const list = modelList.map((item) => {
|
|
||||||
const priceStr = `(${formatPrice(item.price, 1000)}元/1k Tokens)`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: item.model,
|
|
||||||
label: `${item.name}${priceStr}`
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!item.value && list.length > 0) {
|
|
||||||
onChangeModel(list[0].value);
|
|
||||||
}
|
|
||||||
}, [item.value, list, onChangeModel]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MySelect
|
|
||||||
minW={'350px'}
|
|
||||||
width={'100%'}
|
|
||||||
value={item.value}
|
|
||||||
list={list}
|
|
||||||
onchange={onChangeModel}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SelectDatasetRender = React.memo(function SelectDatasetRender({
|
|
||||||
item,
|
|
||||||
moduleId
|
|
||||||
}: RenderProps) {
|
|
||||||
const theme = useTheme();
|
|
||||||
const { mode } = useFlowProviderStore();
|
|
||||||
const { allDatasets, loadAllDatasets } = useDatasetStore();
|
|
||||||
const {
|
|
||||||
isOpen: isOpenKbSelect,
|
|
||||||
onOpen: onOpenKbSelect,
|
|
||||||
onClose: onCloseKbSelect
|
|
||||||
} = useDisclosure();
|
|
||||||
|
|
||||||
const selectedDatasets = useMemo(() => {
|
|
||||||
const value = item.value as SelectedDatasetType;
|
|
||||||
return allDatasets.filter((dataset) => value?.find((item) => item.datasetId === dataset._id));
|
|
||||||
}, [allDatasets, item.value]);
|
|
||||||
|
|
||||||
useQuery(['loadAllDatasets'], loadAllDatasets);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Grid gridTemplateColumns={'repeat(2, minmax(0, 1fr))'} gridGap={4} minW={'350px'} w={'100%'}>
|
|
||||||
<Button h={'36px'} onClick={onOpenKbSelect}>
|
|
||||||
选择知识库
|
|
||||||
</Button>
|
|
||||||
{selectedDatasets.map((item) => (
|
|
||||||
<Flex
|
|
||||||
key={item._id}
|
|
||||||
alignItems={'center'}
|
|
||||||
h={'36px'}
|
|
||||||
border={theme.borders.base}
|
|
||||||
px={2}
|
|
||||||
borderRadius={'md'}
|
|
||||||
>
|
|
||||||
<Avatar src={item.avatar} w={'24px'}></Avatar>
|
|
||||||
<Box
|
|
||||||
ml={3}
|
|
||||||
flex={'1 0 0'}
|
|
||||||
w={0}
|
|
||||||
className="textEllipsis"
|
|
||||||
fontWeight={'bold'}
|
|
||||||
fontSize={['md', 'lg', 'xl']}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
{isOpenKbSelect && (
|
|
||||||
<DatasetSelectModal
|
|
||||||
isOpen={isOpenKbSelect}
|
|
||||||
defaultSelectedDatasets={item.value}
|
|
||||||
onChange={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
key: item.key,
|
|
||||||
type: 'updateInput',
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
onClose={onCloseKbSelect}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SelectAppRender = React.memo(function SelectAppRender({ item, moduleId }: RenderProps) {
|
|
||||||
const { filterAppIds } = useFlowProviderStore();
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const {
|
|
||||||
isOpen: isOpenSelectApp,
|
|
||||||
onOpen: onOpenSelectApp,
|
|
||||||
onClose: onCloseSelectApp
|
|
||||||
} = useDisclosure();
|
|
||||||
|
|
||||||
const value = item.value as SelectAppItemType | undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box onClick={onOpenSelectApp}>
|
|
||||||
{!value ? (
|
|
||||||
<Button variant={'base'} w={'100%'}>
|
|
||||||
选择应用
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Flex alignItems={'center'} border={theme.borders.base} borderRadius={'md'} px={3} py={2}>
|
|
||||||
<Avatar src={value?.logo} />
|
|
||||||
<Box fontWeight={'bold'} ml={1}>
|
|
||||||
{value?.name}
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{isOpenSelectApp && (
|
|
||||||
<SelectAppModal
|
|
||||||
defaultApps={item.value?.id ? [item.value.id] : []}
|
|
||||||
filterAppIds={filterAppIds}
|
|
||||||
onClose={onCloseSelectApp}
|
|
||||||
onSuccess={(e) => {
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: 'app',
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
value: e[0]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const SelectDatasetParamsRender = React.memo(function SelectDatasetParamsRender({
|
|
||||||
item,
|
|
||||||
inputs = [],
|
|
||||||
moduleId
|
|
||||||
}: RenderProps) {
|
|
||||||
const { nodes } = useFlowProviderStore();
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [data, setData] = useState({
|
|
||||||
searchMode: DatasetSearchModeEnum.embedding,
|
|
||||||
limit: 5,
|
|
||||||
similarity: 0.5
|
|
||||||
});
|
|
||||||
|
|
||||||
const tokenLimit = useMemo(() => {
|
|
||||||
let maxTokens = 3000;
|
|
||||||
|
|
||||||
nodes.forEach((item) => {
|
|
||||||
if (item.type === FlowNodeTypeEnum.chatNode) {
|
|
||||||
const model =
|
|
||||||
item.data.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
|
|
||||||
const quoteMaxToken =
|
|
||||||
chatModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
|
|
||||||
|
|
||||||
maxTokens = Math.max(maxTokens, quoteMaxToken);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return maxTokens;
|
|
||||||
}, [nodes]);
|
|
||||||
|
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
inputs.forEach((input) => {
|
|
||||||
// @ts-ignore
|
|
||||||
if (data[input.key] !== undefined) {
|
|
||||||
setData((state) => ({
|
|
||||||
...state,
|
|
||||||
[input.key]: input.value
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [inputs]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
variant={'base'}
|
|
||||||
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
|
|
||||||
onClick={onOpen}
|
|
||||||
>
|
|
||||||
{t('core.dataset.search.Params Setting')}
|
|
||||||
</Button>
|
|
||||||
{isOpen && (
|
|
||||||
<DatasetParamsModal
|
|
||||||
{...data}
|
|
||||||
maxTokens={tokenLimit}
|
|
||||||
onClose={onClose}
|
|
||||||
onSuccess={(e) => {
|
|
||||||
for (let key in e) {
|
|
||||||
const item = inputs.find((input) => input.key === key);
|
|
||||||
if (!item) continue;
|
|
||||||
onChangeNode({
|
|
||||||
moduleId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key,
|
|
||||||
value: {
|
|
||||||
...item,
|
|
||||||
//@ts-ignore
|
|
||||||
value: e[key]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
import { EditNodeFieldType, FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
onChangeNode,
|
||||||
|
useFlowProviderStore,
|
||||||
|
useFlowProviderStoreType
|
||||||
|
} from '../../../FlowProvider';
|
||||||
|
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
import TargetHandle from '../TargetHandle';
|
||||||
|
import MyIcon from '@/components/Icon';
|
||||||
|
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
const FieldEditModal = dynamic(() => import('../FieldEditModal'));
|
||||||
|
|
||||||
|
type Props = FlowNodeInputItemType & {
|
||||||
|
moduleId: string;
|
||||||
|
inputKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const InputLabel = ({
|
||||||
|
moduleId,
|
||||||
|
inputKey,
|
||||||
|
mode,
|
||||||
|
...item
|
||||||
|
}: Props & {
|
||||||
|
mode: useFlowProviderStoreType['mode'];
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
required = false,
|
||||||
|
description,
|
||||||
|
edit,
|
||||||
|
label,
|
||||||
|
type,
|
||||||
|
valueType,
|
||||||
|
showTargetInApp,
|
||||||
|
showTargetInPlugin
|
||||||
|
} = item;
|
||||||
|
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||||
|
|
||||||
|
const targetHandle = useMemo(() => {
|
||||||
|
if (type === FlowNodeInputTypeEnum.target) return true;
|
||||||
|
if (mode === 'app' && showTargetInApp) return true;
|
||||||
|
if (mode === 'plugin' && showTargetInPlugin) return true;
|
||||||
|
return false;
|
||||||
|
}, [mode, showTargetInApp, showTargetInPlugin, type]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex className="nodrag" cursor={'default'} alignItems={'center'} position={'relative'}>
|
||||||
|
<Box position={'relative'}>
|
||||||
|
{t(label)}
|
||||||
|
{description && (
|
||||||
|
<MyTooltip label={t(description)} forceShow>
|
||||||
|
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||||
|
</MyTooltip>
|
||||||
|
)}
|
||||||
|
{required && (
|
||||||
|
<Box
|
||||||
|
position={'absolute'}
|
||||||
|
top={'-2px'}
|
||||||
|
right={'-8px'}
|
||||||
|
color={'red.500'}
|
||||||
|
fontWeight={'bold'}
|
||||||
|
>
|
||||||
|
*
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{targetHandle && <TargetHandle handleKey={inputKey} valueType={valueType} />}
|
||||||
|
|
||||||
|
{edit && (
|
||||||
|
<>
|
||||||
|
<MyIcon
|
||||||
|
name={'settingLight'}
|
||||||
|
w={'14px'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
ml={3}
|
||||||
|
_hover={{ color: 'myBlue.600' }}
|
||||||
|
onClick={() =>
|
||||||
|
setEditField({
|
||||||
|
inputType: type,
|
||||||
|
valueType: valueType,
|
||||||
|
key: inputKey,
|
||||||
|
required,
|
||||||
|
label,
|
||||||
|
description
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MyIcon
|
||||||
|
className="delete"
|
||||||
|
name={'delete'}
|
||||||
|
w={'14px'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
ml={2}
|
||||||
|
_hover={{ color: 'red.500' }}
|
||||||
|
onClick={() => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'delInput',
|
||||||
|
key: inputKey,
|
||||||
|
value: ''
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{!!editField?.key && (
|
||||||
|
<FieldEditModal
|
||||||
|
editField={item.editField}
|
||||||
|
keys={[editField.key]}
|
||||||
|
defaultField={editField}
|
||||||
|
onClose={() => setEditField(undefined)}
|
||||||
|
onSubmit={({ data, changeKey }) => {
|
||||||
|
if (!data.inputType || !data.key || !data.label) return;
|
||||||
|
|
||||||
|
const newInput: FlowNodeInputItemType = {
|
||||||
|
...item,
|
||||||
|
type: data.inputType,
|
||||||
|
valueType: data.valueType,
|
||||||
|
key: data.key,
|
||||||
|
required: data.required,
|
||||||
|
label: data.label,
|
||||||
|
description: data.description
|
||||||
|
};
|
||||||
|
|
||||||
|
if (changeKey) {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'replaceInput',
|
||||||
|
key: editField.key,
|
||||||
|
value: newInput
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: newInput.key,
|
||||||
|
value: newInput
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setEditField(undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(function (props: Props) {
|
||||||
|
const { mode } = useFlowProviderStore();
|
||||||
|
|
||||||
|
return <InputLabel {...props} mode={mode} />;
|
||||||
|
});
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
import InputLabel from './Label';
|
||||||
|
import type { RenderInputProps } from './type.d';
|
||||||
|
import { useFlowProviderStore, type useFlowProviderStoreType } from '../../../FlowProvider';
|
||||||
|
|
||||||
|
const RenderList: {
|
||||||
|
types: `${FlowNodeInputTypeEnum}`[];
|
||||||
|
Component: React.ComponentType<RenderInputProps>;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.input],
|
||||||
|
Component: dynamic(() => import('./templates/TextInput'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.numberInput],
|
||||||
|
Component: dynamic(() => import('./templates/NumberInput'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.switch],
|
||||||
|
Component: dynamic(() => import('./templates/Switch'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.textarea],
|
||||||
|
Component: dynamic(() => import('./templates/Textarea'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.select],
|
||||||
|
Component: dynamic(() => import('./templates/Select'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.slider],
|
||||||
|
Component: dynamic(() => import('./templates/Slider'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.selectApp],
|
||||||
|
Component: dynamic(() => import('./templates/SelectApp'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.aiSettings],
|
||||||
|
Component: dynamic(() => import('./templates/AiSetting'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [
|
||||||
|
FlowNodeInputTypeEnum.selectChatModel,
|
||||||
|
FlowNodeInputTypeEnum.selectCQModel,
|
||||||
|
FlowNodeInputTypeEnum.selectExtractModel
|
||||||
|
],
|
||||||
|
Component: dynamic(() => import('./templates/SelectAiModel'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.selectDataset],
|
||||||
|
Component: dynamic(() => import('./templates/SelectDataset'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.selectDatasetParamsModal],
|
||||||
|
Component: dynamic(() => import('./templates/SelectDatasetParams'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types: [FlowNodeInputTypeEnum.addInputParam],
|
||||||
|
Component: dynamic(() => import('./templates/AddInputParam'))
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
flowInputList: FlowNodeInputItemType[];
|
||||||
|
moduleId: string;
|
||||||
|
CustomComponent?: Record<string, (e: FlowNodeInputItemType) => React.ReactNode>;
|
||||||
|
};
|
||||||
|
const RenderInput = ({
|
||||||
|
flowInputList,
|
||||||
|
moduleId,
|
||||||
|
CustomComponent = {},
|
||||||
|
mode
|
||||||
|
}: Props & {
|
||||||
|
mode: useFlowProviderStoreType['mode'];
|
||||||
|
}) => {
|
||||||
|
const sortInputs = useMemo(
|
||||||
|
() =>
|
||||||
|
flowInputList.sort((a, b) => {
|
||||||
|
if (a.type === FlowNodeInputTypeEnum.addInputParam) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (b.type === FlowNodeInputTypeEnum.addInputParam) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.type === FlowNodeInputTypeEnum.switch) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}),
|
||||||
|
[flowInputList]
|
||||||
|
);
|
||||||
|
const filterInputs = useMemo(
|
||||||
|
() =>
|
||||||
|
sortInputs.filter((input) => {
|
||||||
|
if (mode === 'app' && input.hideInApp) return false;
|
||||||
|
if (mode === 'plugin' && input.hideInPlugin) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
[mode, sortInputs]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{filterInputs.map((input) => {
|
||||||
|
const RenderComponent = (() => {
|
||||||
|
if (input.type === FlowNodeInputTypeEnum.custom && CustomComponent[input.key]) {
|
||||||
|
return <>{CustomComponent[input.key]({ ...input })}</>;
|
||||||
|
}
|
||||||
|
const Component = RenderList.find((item) => item.types.includes(input.type))?.Component;
|
||||||
|
|
||||||
|
if (!Component) return null;
|
||||||
|
return <Component inputs={filterInputs} item={input} moduleId={moduleId} />;
|
||||||
|
})();
|
||||||
|
|
||||||
|
return (
|
||||||
|
input.type !== FlowNodeInputTypeEnum.hidden && (
|
||||||
|
<Box key={input.key} _notLast={{ mb: 7 }} position={'relative'}>
|
||||||
|
{!!input.label && <InputLabel moduleId={moduleId} inputKey={input.key} {...input} />}
|
||||||
|
{!!RenderComponent && (
|
||||||
|
<Box mt={2} className={'nodrag'}>
|
||||||
|
{RenderComponent}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(function (props: Props) {
|
||||||
|
const { mode } = useFlowProviderStore();
|
||||||
|
return <RenderInput {...props} mode={mode} />;
|
||||||
|
});
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import { Button } from '@chakra-ui/react';
|
||||||
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { EditNodeFieldType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
const FieldEditModal = dynamic(() => import('../../FieldEditModal'));
|
||||||
|
|
||||||
|
const AddInputParam = ({ inputs = [], item, moduleId }: RenderInputProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant={'base'}
|
||||||
|
leftIcon={<SmallAddIcon />}
|
||||||
|
onClick={() => {
|
||||||
|
setEditField(item.defaultEditField || {});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('core.module.input.Add Input')}
|
||||||
|
</Button>
|
||||||
|
{!!editField && (
|
||||||
|
<FieldEditModal
|
||||||
|
editField={item.editField}
|
||||||
|
defaultField={editField}
|
||||||
|
keys={inputs.map((input) => input.key)}
|
||||||
|
onClose={() => setEditField(undefined)}
|
||||||
|
onSubmit={({ data }) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'addInput',
|
||||||
|
key: data.key,
|
||||||
|
value: {
|
||||||
|
key: data.key,
|
||||||
|
valueType: data.valueType,
|
||||||
|
label: data.label,
|
||||||
|
type: data.inputType,
|
||||||
|
required: data.required,
|
||||||
|
description: data.description,
|
||||||
|
edit: true,
|
||||||
|
editField: item.editField
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setEditField(undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(AddInputParam);
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { Button, useDisclosure } from '@chakra-ui/react';
|
||||||
|
import { AIChatModuleProps } from '@fastgpt/global/core/module/node/type';
|
||||||
|
import MyIcon from '@/components/Icon';
|
||||||
|
import AIChatSettingsModal from '@/components/core/module/AIChatSettingsModal';
|
||||||
|
|
||||||
|
const AiSettingRender = ({ inputs = [], moduleId }: RenderInputProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const chatModulesData = useMemo(() => {
|
||||||
|
const obj: Record<string, any> = {};
|
||||||
|
inputs.forEach((item) => {
|
||||||
|
obj[item.key] = item.value;
|
||||||
|
});
|
||||||
|
return obj as AIChatModuleProps;
|
||||||
|
}, [inputs]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
isOpen: isOpenAIChatSetting,
|
||||||
|
onOpen: onOpenAIChatSetting,
|
||||||
|
onClose: onCloseAIChatSetting
|
||||||
|
} = useDisclosure();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant={'base'}
|
||||||
|
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
|
||||||
|
onClick={onOpenAIChatSetting}
|
||||||
|
>
|
||||||
|
{t('app.AI Settings')}
|
||||||
|
</Button>
|
||||||
|
{isOpenAIChatSetting && (
|
||||||
|
<AIChatSettingsModal
|
||||||
|
isAdEdit
|
||||||
|
onClose={onCloseAIChatSetting}
|
||||||
|
onSuccess={(e) => {
|
||||||
|
for (let key in e) {
|
||||||
|
const item = inputs.find((input) => input.key === key);
|
||||||
|
if (!item) continue;
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
//@ts-ignore
|
||||||
|
value: e[key]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onCloseAIChatSetting();
|
||||||
|
}}
|
||||||
|
defaultData={chatModulesData}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(AiSettingRender);
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import {
|
||||||
|
NumberDecrementStepper,
|
||||||
|
NumberIncrementStepper,
|
||||||
|
NumberInput,
|
||||||
|
NumberInputField,
|
||||||
|
NumberInputStepper
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
|
||||||
|
const NumberInputRender = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
return (
|
||||||
|
<NumberInput
|
||||||
|
defaultValue={item.value}
|
||||||
|
min={item.min}
|
||||||
|
max={item.max}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: Number(e)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
<NumberInputStepper>
|
||||||
|
<NumberIncrementStepper />
|
||||||
|
<NumberDecrementStepper />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(NumberInputRender);
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import MySelect from '@/components/Select';
|
||||||
|
|
||||||
|
const SelectRender = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
return (
|
||||||
|
<MySelect
|
||||||
|
width={'100%'}
|
||||||
|
value={item.value}
|
||||||
|
list={item.list || []}
|
||||||
|
onchange={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(SelectRender);
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
import React, { useCallback, useEffect } from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import MySelect from '@/components/Select';
|
||||||
|
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
|
import { chatModelList, cqModelList, extractModelList } from '@/web/common/system/staticData';
|
||||||
|
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||||
|
|
||||||
|
const SelectAiModelRender = ({ item, inputs = [], moduleId }: RenderInputProps) => {
|
||||||
|
const modelList = (() => {
|
||||||
|
if (item.type === FlowNodeInputTypeEnum.selectChatModel) return chatModelList;
|
||||||
|
if (item.type === FlowNodeInputTypeEnum.selectCQModel) return cqModelList;
|
||||||
|
if (item.type === FlowNodeInputTypeEnum.selectExtractModel) return extractModelList;
|
||||||
|
|
||||||
|
return [];
|
||||||
|
})().map((item) => ({
|
||||||
|
model: item.model,
|
||||||
|
name: item.name,
|
||||||
|
maxResponse: item.maxResponse,
|
||||||
|
price: item.price
|
||||||
|
}));
|
||||||
|
|
||||||
|
const onChangeModel = useCallback(
|
||||||
|
(e: string) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// update max tokens
|
||||||
|
const model = modelList.find((item) => item.model === e) || modelList[0];
|
||||||
|
if (!model) return;
|
||||||
|
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: 'maxToken',
|
||||||
|
value: {
|
||||||
|
...inputs.find((input) => input.key === 'maxToken'),
|
||||||
|
markList: [
|
||||||
|
{ label: '100', value: 100 },
|
||||||
|
{ label: `${model.maxResponse}`, value: model.maxResponse }
|
||||||
|
],
|
||||||
|
max: model.maxResponse,
|
||||||
|
value: model.maxResponse / 2
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[inputs, item, modelList, moduleId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const list = modelList.map((item) => {
|
||||||
|
const priceStr = `(${formatPrice(item.price, 1000)}元/1k Tokens)`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: item.model,
|
||||||
|
label: `${item.name}${priceStr}`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!item.value && list.length > 0) {
|
||||||
|
onChangeModel(list[0].value);
|
||||||
|
}
|
||||||
|
}, [item.value, list, onChangeModel]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MySelect
|
||||||
|
minW={'350px'}
|
||||||
|
width={'100%'}
|
||||||
|
value={item.value}
|
||||||
|
list={list}
|
||||||
|
onchange={onChangeModel}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(SelectAiModelRender);
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import {
|
||||||
|
onChangeNode,
|
||||||
|
useFlowProviderStore,
|
||||||
|
type useFlowProviderStoreType
|
||||||
|
} from '../../../../FlowProvider';
|
||||||
|
import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||||
|
import { SelectAppItemType } from '@fastgpt/global/core/module/type';
|
||||||
|
import Avatar from '@/components/Avatar';
|
||||||
|
import SelectAppModal from '../../../../SelectAppModal';
|
||||||
|
|
||||||
|
const SelectAppRender = ({
|
||||||
|
item,
|
||||||
|
moduleId,
|
||||||
|
filterAppIds
|
||||||
|
}: RenderInputProps & {
|
||||||
|
filterAppIds: useFlowProviderStoreType['filterAppIds'];
|
||||||
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const {
|
||||||
|
isOpen: isOpenSelectApp,
|
||||||
|
onOpen: onOpenSelectApp,
|
||||||
|
onClose: onCloseSelectApp
|
||||||
|
} = useDisclosure();
|
||||||
|
|
||||||
|
const value = item.value as SelectAppItemType | undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box onClick={onOpenSelectApp}>
|
||||||
|
{!value ? (
|
||||||
|
<Button variant={'base'} w={'100%'}>
|
||||||
|
选择应用
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Flex alignItems={'center'} border={theme.borders.base} borderRadius={'md'} px={3} py={2}>
|
||||||
|
<Avatar src={value?.logo} />
|
||||||
|
<Box fontWeight={'bold'} ml={1}>
|
||||||
|
{value?.name}
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{isOpenSelectApp && (
|
||||||
|
<SelectAppModal
|
||||||
|
defaultApps={item.value?.id ? [item.value.id] : []}
|
||||||
|
filterAppIds={filterAppIds}
|
||||||
|
onClose={onCloseSelectApp}
|
||||||
|
onSuccess={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: 'app',
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e[0]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(function (props: RenderInputProps) {
|
||||||
|
const { filterAppIds } = useFlowProviderStore();
|
||||||
|
return <SelectAppRender {...props} filterAppIds={filterAppIds} />;
|
||||||
|
});
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import { Box, Button, Flex, Grid, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||||
|
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||||
|
import { SelectedDatasetType } from '@fastgpt/global/core/module/api';
|
||||||
|
import Avatar from '@/components/Avatar';
|
||||||
|
import DatasetSelectModal from '@/components/core/module/DatasetSelectModal';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
const SelectDatasetRender = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const { allDatasets, loadAllDatasets } = useDatasetStore();
|
||||||
|
const {
|
||||||
|
isOpen: isOpenKbSelect,
|
||||||
|
onOpen: onOpenKbSelect,
|
||||||
|
onClose: onCloseKbSelect
|
||||||
|
} = useDisclosure();
|
||||||
|
|
||||||
|
const selectedDatasets = useMemo(() => {
|
||||||
|
const value = item.value as SelectedDatasetType;
|
||||||
|
return allDatasets.filter((dataset) => value?.find((item) => item.datasetId === dataset._id));
|
||||||
|
}, [allDatasets, item.value]);
|
||||||
|
|
||||||
|
useQuery(['loadAllDatasets'], loadAllDatasets);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Grid gridTemplateColumns={'repeat(2, minmax(0, 1fr))'} gridGap={4} minW={'350px'} w={'100%'}>
|
||||||
|
<Button h={'36px'} onClick={onOpenKbSelect}>
|
||||||
|
选择知识库
|
||||||
|
</Button>
|
||||||
|
{selectedDatasets.map((item) => (
|
||||||
|
<Flex
|
||||||
|
key={item._id}
|
||||||
|
alignItems={'center'}
|
||||||
|
h={'36px'}
|
||||||
|
border={theme.borders.base}
|
||||||
|
px={2}
|
||||||
|
borderRadius={'md'}
|
||||||
|
>
|
||||||
|
<Avatar src={item.avatar} w={'24px'}></Avatar>
|
||||||
|
<Box
|
||||||
|
ml={3}
|
||||||
|
flex={'1 0 0'}
|
||||||
|
w={0}
|
||||||
|
className="textEllipsis"
|
||||||
|
fontWeight={'bold'}
|
||||||
|
fontSize={['md', 'lg', 'xl']}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
{isOpenKbSelect && (
|
||||||
|
<DatasetSelectModal
|
||||||
|
isOpen={isOpenKbSelect}
|
||||||
|
defaultSelectedDatasets={item.value}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
key: item.key,
|
||||||
|
type: 'updateInput',
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onClose={onCloseKbSelect}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(SelectDatasetRender);
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode, useFlowProviderStore } from '../../../../FlowProvider';
|
||||||
|
import { Button, useDisclosure } from '@chakra-ui/react';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||||
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
|
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||||
|
import { chatModelList } from '@/web/common/system/staticData';
|
||||||
|
import MyIcon from '@/components/Icon';
|
||||||
|
import DatasetParamsModal from '@/components/core/module/DatasetParamsModal';
|
||||||
|
|
||||||
|
const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
|
||||||
|
const { nodes } = useFlowProviderStore();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [data, setData] = useState({
|
||||||
|
searchMode: DatasetSearchModeEnum.embedding,
|
||||||
|
limit: 5,
|
||||||
|
similarity: 0.5
|
||||||
|
});
|
||||||
|
|
||||||
|
const tokenLimit = useMemo(() => {
|
||||||
|
let maxTokens = 3000;
|
||||||
|
|
||||||
|
nodes.forEach((item) => {
|
||||||
|
if (item.type === FlowNodeTypeEnum.chatNode) {
|
||||||
|
const model =
|
||||||
|
item.data.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
|
||||||
|
const quoteMaxToken =
|
||||||
|
chatModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
|
||||||
|
|
||||||
|
maxTokens = Math.max(maxTokens, quoteMaxToken);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return maxTokens;
|
||||||
|
}, [nodes]);
|
||||||
|
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
inputs.forEach((input) => {
|
||||||
|
// @ts-ignore
|
||||||
|
if (data[input.key] !== undefined) {
|
||||||
|
setData((state) => ({
|
||||||
|
...state,
|
||||||
|
[input.key]: input.value
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [inputs]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant={'base'}
|
||||||
|
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
|
||||||
|
onClick={onOpen}
|
||||||
|
>
|
||||||
|
{t('core.dataset.search.Params Setting')}
|
||||||
|
</Button>
|
||||||
|
{isOpen && (
|
||||||
|
<DatasetParamsModal
|
||||||
|
{...data}
|
||||||
|
maxTokens={tokenLimit}
|
||||||
|
onClose={onClose}
|
||||||
|
onSuccess={(e) => {
|
||||||
|
for (let key in e) {
|
||||||
|
const item = inputs.find((input) => input.key === key);
|
||||||
|
if (!item) continue;
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
//@ts-ignore
|
||||||
|
value: e[key]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(SelectDatasetParam);
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import MySlider from '@/components/Slider';
|
||||||
|
|
||||||
|
const SliderRender = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Box pt={5} pb={4} px={2}>
|
||||||
|
<MySlider
|
||||||
|
markList={item.markList}
|
||||||
|
width={'100%'}
|
||||||
|
min={item.min || 0}
|
||||||
|
max={item.max}
|
||||||
|
step={item.step || 1}
|
||||||
|
value={item.value}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(SliderRender);
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { Switch } from '@chakra-ui/react';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
|
||||||
|
const SwitchRender = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
size={'lg'}
|
||||||
|
isChecked={item.value}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e.target.checked
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(SwitchRender);
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { Input } from '@chakra-ui/react';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
|
||||||
|
const TextInput = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
placeholder={item.placeholder}
|
||||||
|
defaultValue={item.value}
|
||||||
|
onBlur={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e.target.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(TextInput);
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { RenderInputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import PromptTextarea from '@/components/common/Textarea/PromptTextarea';
|
||||||
|
|
||||||
|
const TextareaRender = ({ item, moduleId }: RenderInputProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<PromptTextarea
|
||||||
|
title={t(item.label)}
|
||||||
|
rows={5}
|
||||||
|
bg={'myWhite.400'}
|
||||||
|
placeholder={t(item.placeholder || '')}
|
||||||
|
resize={'both'}
|
||||||
|
defaultValue={item.value}
|
||||||
|
onBlur={(e) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: e.target.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(TextareaRender);
|
||||||
7
projects/app/src/components/core/module/Flow/components/render/RenderInput/type.d.ts
vendored
Normal file
7
projects/app/src/components/core/module/Flow/components/render/RenderInput/type.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
|
||||||
|
export type RenderInputProps = {
|
||||||
|
inputs?: FlowNodeInputItemType[];
|
||||||
|
item: FlowNodeInputItemType;
|
||||||
|
moduleId: string;
|
||||||
|
};
|
||||||
@ -1,34 +1,30 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
import { EditNodeFieldType, FlowNodeOutputItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
import type { FlowNodeOutputItemType } from '@fastgpt/global/core/module/node/type';
|
import React, { useState } from 'react';
|
||||||
import { Box, Flex } from '@chakra-ui/react';
|
|
||||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
|
||||||
import SourceHandle from './SourceHandle';
|
|
||||||
import MyIcon from '@/components/Icon';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import { onChangeNode } from '../../FlowProvider';
|
|
||||||
import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
|
import MyIcon from '@/components/Icon';
|
||||||
|
import { onChangeNode } from '../../../FlowProvider';
|
||||||
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
import SourceHandle from '../SourceHandle';
|
||||||
|
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
import type { EditFieldType, EditFieldModeType } from '../modules/FieldEditModal';
|
const FieldEditModal = dynamic(() => import('../FieldEditModal'));
|
||||||
const FieldEditModal = dynamic(() => import('../modules/FieldEditModal'));
|
|
||||||
|
|
||||||
export const Label = ({
|
const OutputLabel = ({
|
||||||
moduleId,
|
moduleId,
|
||||||
outputKey,
|
outputKey,
|
||||||
outputs,
|
outputs,
|
||||||
editFiledType = 'output',
|
|
||||||
...item
|
...item
|
||||||
}: FlowNodeOutputItemType & {
|
}: FlowNodeOutputItemType & {
|
||||||
outputKey: string;
|
outputKey: string;
|
||||||
moduleId: string;
|
moduleId: string;
|
||||||
outputs: FlowNodeOutputItemType[];
|
outputs: FlowNodeOutputItemType[];
|
||||||
editFiledType?: EditFieldModeType;
|
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { label = '', description, edit } = item;
|
const { label = '', description, edit } = item;
|
||||||
const [editField, setEditField] = useState<EditFieldType>();
|
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
@ -48,10 +44,11 @@ export const Label = ({
|
|||||||
_hover={{ color: 'myBlue.600' }}
|
_hover={{ color: 'myBlue.600' }}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setEditField({
|
setEditField({
|
||||||
label: item.label,
|
|
||||||
valueType: item.valueType,
|
|
||||||
key: outputKey,
|
key: outputKey,
|
||||||
description: item.description
|
label: item.label,
|
||||||
|
description: item.description,
|
||||||
|
valueType: item.valueType,
|
||||||
|
outputType: item.type
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -79,29 +76,41 @@ export const Label = ({
|
|||||||
)}
|
)}
|
||||||
<Box>{t(label)}</Box>
|
<Box>{t(label)}</Box>
|
||||||
|
|
||||||
|
{item.type === FlowNodeOutputTypeEnum.source && (
|
||||||
|
<SourceHandle handleKey={outputKey} valueType={item.valueType} />
|
||||||
|
)}
|
||||||
|
|
||||||
{!!editField && (
|
{!!editField && (
|
||||||
<FieldEditModal
|
<FieldEditModal
|
||||||
mode={editFiledType}
|
editField={item.editField}
|
||||||
defaultField={editField}
|
defaultField={editField}
|
||||||
|
keys={[outputKey]}
|
||||||
onClose={() => setEditField(undefined)}
|
onClose={() => setEditField(undefined)}
|
||||||
onSubmit={(e) => {
|
onSubmit={({ data, changeKey }) => {
|
||||||
const data = {
|
if (!data.outputType || !data.key) return;
|
||||||
|
|
||||||
|
const newOutput: FlowNodeOutputItemType = {
|
||||||
...item,
|
...item,
|
||||||
...e
|
type: data.outputType,
|
||||||
|
valueType: data.valueType,
|
||||||
|
key: data.key,
|
||||||
|
label: data.label,
|
||||||
|
description: data.description
|
||||||
};
|
};
|
||||||
if (editField.key === data.key) {
|
|
||||||
onChangeNode({
|
if (changeKey) {
|
||||||
moduleId,
|
|
||||||
type: 'updateOutput',
|
|
||||||
key: data.key,
|
|
||||||
value: data
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
moduleId,
|
moduleId,
|
||||||
type: 'replaceOutput',
|
type: 'replaceOutput',
|
||||||
key: editField.key,
|
key: editField.key,
|
||||||
value: data
|
value: newOutput
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'updateOutput',
|
||||||
|
key: newOutput.key,
|
||||||
|
value: newOutput
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,48 +122,4 @@ export const Label = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RenderOutput = ({
|
export default React.memo(OutputLabel);
|
||||||
moduleId,
|
|
||||||
flowOutputList,
|
|
||||||
editFiledType
|
|
||||||
}: {
|
|
||||||
moduleId: string;
|
|
||||||
flowOutputList: FlowNodeOutputItemType[];
|
|
||||||
editFiledType?: EditFieldModeType;
|
|
||||||
}) => {
|
|
||||||
const sortOutput = useMemo(
|
|
||||||
() =>
|
|
||||||
[...flowOutputList].sort((a, b) => {
|
|
||||||
if (a.key === ModuleOutputKeyEnum.finish) return -1;
|
|
||||||
if (b.key === ModuleOutputKeyEnum.finish) return 1;
|
|
||||||
return 0;
|
|
||||||
}),
|
|
||||||
[flowOutputList]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{sortOutput.map(
|
|
||||||
(item) =>
|
|
||||||
item.type !== FlowNodeOutputTypeEnum.hidden && (
|
|
||||||
<Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}>
|
|
||||||
<Label
|
|
||||||
editFiledType={editFiledType}
|
|
||||||
moduleId={moduleId}
|
|
||||||
outputKey={item.key}
|
|
||||||
outputs={sortOutput}
|
|
||||||
{...item}
|
|
||||||
/>
|
|
||||||
<Box mt={FlowNodeOutputTypeEnum.answer ? 0 : 2} className={'nodrag'}>
|
|
||||||
{item.type === FlowNodeOutputTypeEnum.source && (
|
|
||||||
<SourceHandle handleKey={item.key} valueType={item.valueType} />
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(RenderOutput);
|
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import type { FlowNodeOutputItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
|
import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||||
|
import OutputLabel from './Label';
|
||||||
|
import { RenderOutputProps } from './type';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
const RenderList: {
|
||||||
|
types: `${FlowNodeOutputTypeEnum}`[];
|
||||||
|
Component: React.ComponentType<RenderOutputProps>;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
types: [FlowNodeOutputTypeEnum.addOutputParam],
|
||||||
|
Component: dynamic(() => import('./templates/AddOutputParam'))
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const RenderOutput = ({
|
||||||
|
moduleId,
|
||||||
|
flowOutputList
|
||||||
|
}: {
|
||||||
|
moduleId: string;
|
||||||
|
flowOutputList: FlowNodeOutputItemType[];
|
||||||
|
}) => {
|
||||||
|
const sortOutputs = useMemo(
|
||||||
|
() =>
|
||||||
|
[...flowOutputList].sort((a, b) => {
|
||||||
|
if (a.type === FlowNodeOutputTypeEnum.addOutputParam) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (b.type === FlowNodeOutputTypeEnum.addOutputParam) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.key === ModuleOutputKeyEnum.finish) return -1;
|
||||||
|
if (b.key === ModuleOutputKeyEnum.finish) return 1;
|
||||||
|
return 0;
|
||||||
|
}),
|
||||||
|
[flowOutputList]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{sortOutputs.map((output) => {
|
||||||
|
const RenderComponent = (() => {
|
||||||
|
const Component = RenderList.find(
|
||||||
|
(item) => output.type && item.types.includes(output.type)
|
||||||
|
)?.Component;
|
||||||
|
|
||||||
|
if (!Component) return null;
|
||||||
|
return <Component outputs={sortOutputs} item={output} moduleId={moduleId} />;
|
||||||
|
})();
|
||||||
|
|
||||||
|
return (
|
||||||
|
output.type !== FlowNodeOutputTypeEnum.hidden && (
|
||||||
|
<Box key={output.key} _notLast={{ mb: 7 }} position={'relative'}>
|
||||||
|
{output.label && (
|
||||||
|
<OutputLabel
|
||||||
|
moduleId={moduleId}
|
||||||
|
outputKey={output.key}
|
||||||
|
outputs={sortOutputs}
|
||||||
|
{...output}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!!RenderComponent && (
|
||||||
|
<Box mt={2} className={'nodrag'}>
|
||||||
|
{RenderComponent}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(RenderOutput);
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import type { RenderOutputProps } from '../type';
|
||||||
|
import { onChangeNode } from '../../../../FlowProvider';
|
||||||
|
import { Box, Button } from '@chakra-ui/react';
|
||||||
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
import { EditNodeFieldType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
|
||||||
|
const FieldEditModal = dynamic(() => import('../../FieldEditModal'));
|
||||||
|
|
||||||
|
const AddOutputParam = ({ outputs = [], item, moduleId }: RenderOutputProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box textAlign={'right'}>
|
||||||
|
<Button
|
||||||
|
variant={'base'}
|
||||||
|
leftIcon={<SmallAddIcon />}
|
||||||
|
onClick={() => {
|
||||||
|
setEditField(item.defaultEditField || {});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('core.module.output.Add Output')}
|
||||||
|
</Button>
|
||||||
|
{!!editField && (
|
||||||
|
<FieldEditModal
|
||||||
|
editField={item.editField}
|
||||||
|
defaultField={editField}
|
||||||
|
keys={outputs.map((output) => output.key)}
|
||||||
|
onClose={() => setEditField(undefined)}
|
||||||
|
onSubmit={({ data }) => {
|
||||||
|
onChangeNode({
|
||||||
|
moduleId,
|
||||||
|
type: 'addOutput',
|
||||||
|
key: data.key,
|
||||||
|
value: {
|
||||||
|
type: data.outputType,
|
||||||
|
valueType: data.valueType,
|
||||||
|
key: data.key,
|
||||||
|
label: data.label,
|
||||||
|
description: data.description,
|
||||||
|
required: data.required,
|
||||||
|
edit: true,
|
||||||
|
editField: item.editField,
|
||||||
|
targets: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setEditField(undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(AddOutputParam);
|
||||||
7
projects/app/src/components/core/module/Flow/components/render/RenderOutput/type.d.ts
vendored
Normal file
7
projects/app/src/components/core/module/Flow/components/render/RenderOutput/type.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { FlowNodeOutputItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
|
||||||
|
export type RenderOutputProps = {
|
||||||
|
outputs?: FlowNodeOutputItemType[];
|
||||||
|
item: FlowNodeOutputItemType;
|
||||||
|
moduleId: string;
|
||||||
|
};
|
||||||
@ -1,26 +1,26 @@
|
|||||||
import React, { useMemo, useTransition } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Box, BoxProps } from '@chakra-ui/react';
|
import { Box, BoxProps } from '@chakra-ui/react';
|
||||||
import { Handle, Position } from 'reactflow';
|
import { Handle, Position } from 'reactflow';
|
||||||
import { FlowValueTypeStyle, FlowValueTypeMap } from '@/web/core/modules/constants/dataType';
|
import { FlowValueTypeMap } from '@/web/core/modules/constants/dataType';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants';
|
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
|
||||||
|
|
||||||
interface Props extends BoxProps {
|
interface Props extends BoxProps {
|
||||||
handleKey: string;
|
handleKey: string;
|
||||||
valueType?: `${ModuleDataTypeEnum}`;
|
valueType?: `${ModuleIOValueTypeEnum}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
|
const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const valType = valueType ?? ModuleDataTypeEnum.any;
|
const valType = valueType ?? ModuleIOValueTypeEnum.any;
|
||||||
|
|
||||||
const valueStyle = useMemo(
|
const valueStyle = useMemo(
|
||||||
() =>
|
() =>
|
||||||
valueType
|
valueType && FlowValueTypeMap[valueType]
|
||||||
? FlowValueTypeStyle[valueType]
|
? FlowValueTypeMap[valueType]?.handlerStyle
|
||||||
: (FlowValueTypeStyle[ModuleDataTypeEnum.any] as any),
|
: FlowValueTypeMap[ModuleIOValueTypeEnum.any]?.handlerStyle,
|
||||||
[valueType]
|
[valueType]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -34,8 +34,8 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
|
|||||||
>
|
>
|
||||||
<MyTooltip
|
<MyTooltip
|
||||||
label={t('app.module.type', {
|
label={t('app.module.type', {
|
||||||
type: t(FlowValueTypeMap[valType].label),
|
type: t(FlowValueTypeMap[valType]?.label),
|
||||||
example: FlowValueTypeMap[valType].example
|
description: FlowValueTypeMap[valType]?.description
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Handle
|
<Handle
|
||||||
|
|||||||
@ -1,32 +1,31 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Box, BoxProps } from '@chakra-ui/react';
|
import { Box, BoxProps } from '@chakra-ui/react';
|
||||||
import { Handle, OnConnect, Position } from 'reactflow';
|
import { Handle, OnConnect, Position } from 'reactflow';
|
||||||
import { FlowValueTypeStyle, FlowValueTypeMap } from '@/web/core/modules/constants/dataType';
|
import { FlowValueTypeMap } from '@/web/core/modules/constants/dataType';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants';
|
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
|
||||||
|
|
||||||
interface Props extends BoxProps {
|
interface Props extends BoxProps {
|
||||||
handleKey: string;
|
handleKey: string;
|
||||||
valueType?: `${ModuleDataTypeEnum}`;
|
valueType?: `${ModuleIOValueTypeEnum}`;
|
||||||
onConnect?: OnConnect;
|
onConnect?: OnConnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
|
const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const valType = valueType ?? ModuleDataTypeEnum.any;
|
const valType = valueType ?? ModuleIOValueTypeEnum.any;
|
||||||
const valueStyle = useMemo(
|
const valueStyle = useMemo(
|
||||||
() =>
|
() =>
|
||||||
valueType
|
valueType && FlowValueTypeMap[valueType]
|
||||||
? FlowValueTypeStyle[valueType]
|
? FlowValueTypeMap[valueType]?.handlerStyle
|
||||||
: (FlowValueTypeStyle[ModuleDataTypeEnum.any] as any),
|
: FlowValueTypeMap[ModuleIOValueTypeEnum.any]?.handlerStyle,
|
||||||
[valueType]
|
[valueType]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
key={handleKey}
|
|
||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
top={'50%'}
|
top={'50%'}
|
||||||
left={'-16px'}
|
left={'-16px'}
|
||||||
@ -35,8 +34,8 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
|
|||||||
>
|
>
|
||||||
<MyTooltip
|
<MyTooltip
|
||||||
label={t('app.module.type', {
|
label={t('app.module.type', {
|
||||||
type: t(FlowValueTypeMap[valType].label),
|
type: t(FlowValueTypeMap[valType]?.label),
|
||||||
example: FlowValueTypeMap[valType].example
|
description: FlowValueTypeMap[valType]?.description
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Handle
|
<Handle
|
||||||
|
|||||||
@ -2,8 +2,7 @@ import React, { useEffect } from 'react';
|
|||||||
import ReactFlow, { Background, Controls, ReactFlowProvider } from 'reactflow';
|
import ReactFlow, { Background, Controls, ReactFlowProvider } from 'reactflow';
|
||||||
import { Box, Flex, IconButton, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex, IconButton, useDisclosure } from '@chakra-ui/react';
|
||||||
import { SmallCloseIcon } from '@chakra-ui/icons';
|
import { SmallCloseIcon } from '@chakra-ui/icons';
|
||||||
import { edgeOptions, connectionLineStyle } from '@/web/core/modules/constants/flowUi';
|
import { EDGE_TYPE, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
@ -25,14 +24,14 @@ const nodeTypes = {
|
|||||||
[FlowNodeTypeEnum.answerNode]: dynamic(() => import('./components/nodes/NodeAnswer')),
|
[FlowNodeTypeEnum.answerNode]: dynamic(() => import('./components/nodes/NodeAnswer')),
|
||||||
[FlowNodeTypeEnum.classifyQuestion]: dynamic(() => import('./components/nodes/NodeCQNode')),
|
[FlowNodeTypeEnum.classifyQuestion]: dynamic(() => import('./components/nodes/NodeCQNode')),
|
||||||
[FlowNodeTypeEnum.contentExtract]: dynamic(() => import('./components/nodes/NodeExtract')),
|
[FlowNodeTypeEnum.contentExtract]: dynamic(() => import('./components/nodes/NodeExtract')),
|
||||||
[FlowNodeTypeEnum.httpRequest]: dynamic(() => import('./components/nodes/NodeHttp')),
|
[FlowNodeTypeEnum.httpRequest]: NodeSimple,
|
||||||
[FlowNodeTypeEnum.runApp]: NodeSimple,
|
[FlowNodeTypeEnum.runApp]: NodeSimple,
|
||||||
[FlowNodeTypeEnum.pluginInput]: dynamic(() => import('./components/nodes/NodePluginInput')),
|
[FlowNodeTypeEnum.pluginInput]: dynamic(() => import('./components/nodes/NodePluginInput')),
|
||||||
[FlowNodeTypeEnum.pluginOutput]: dynamic(() => import('./components/nodes/NodePluginOutput')),
|
[FlowNodeTypeEnum.pluginOutput]: dynamic(() => import('./components/nodes/NodePluginOutput')),
|
||||||
[FlowNodeTypeEnum.pluginModule]: NodeSimple
|
[FlowNodeTypeEnum.pluginModule]: NodeSimple
|
||||||
};
|
};
|
||||||
const edgeTypes = {
|
const edgeTypes = {
|
||||||
buttonedge: ButtonEdge
|
[EDGE_TYPE]: ButtonEdge
|
||||||
};
|
};
|
||||||
type Props = {
|
type Props = {
|
||||||
modules: ModuleItemType[];
|
modules: ModuleItemType[];
|
||||||
@ -40,7 +39,7 @@ type Props = {
|
|||||||
} & ModuleTemplateProps;
|
} & ModuleTemplateProps;
|
||||||
|
|
||||||
const Container = React.memo(function Container(props: Props) {
|
const Container = React.memo(function Container(props: Props) {
|
||||||
const { modules = [], Header, systemTemplates, pluginTemplates } = props;
|
const { modules = [], Header, templates } = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenTemplate,
|
isOpen: isOpenTemplate,
|
||||||
@ -96,8 +95,10 @@ const Container = React.memo(function Container(props: Props) {
|
|||||||
edges={edges}
|
edges={edges}
|
||||||
minZoom={0.1}
|
minZoom={0.1}
|
||||||
maxZoom={1.5}
|
maxZoom={1.5}
|
||||||
defaultEdgeOptions={edgeOptions}
|
defaultEdgeOptions={{
|
||||||
connectionLineStyle={connectionLineStyle}
|
animated: true
|
||||||
|
}}
|
||||||
|
connectionLineStyle={{ strokeWidth: 2, stroke: '#5A646Es' }}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
edgeTypes={edgeTypes}
|
edgeTypes={edgeTypes}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
@ -115,8 +116,7 @@ const Container = React.memo(function Container(props: Props) {
|
|||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
|
||||||
<ModuleTemplateList
|
<ModuleTemplateList
|
||||||
systemTemplates={systemTemplates}
|
templates={templates}
|
||||||
pluginTemplates={pluginTemplates}
|
|
||||||
isOpen={isOpenTemplate}
|
isOpen={isOpenTemplate}
|
||||||
onClose={onCloseTemplate}
|
onClose={onCloseTemplate}
|
||||||
/>
|
/>
|
||||||
|
|||||||
51
projects/app/src/components/core/module/utils.ts
Normal file
51
projects/app/src/components/core/module/utils.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { FlowNodeOutputTargetItemType } from '@fastgpt/global/core/module/node/type';
|
||||||
|
import { FlowModuleItemType, ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||||
|
import { type Node, type Edge } from 'reactflow';
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@ -25,7 +25,7 @@ export const Prompt_ExtractJson = `你可以从 <对话记录></对话记录>
|
|||||||
|
|
||||||
<字段说明>
|
<字段说明>
|
||||||
1. 下面的 JSON 字符串均按照 JSON Schema 的规则描述。
|
1. 下面的 JSON 字符串均按照 JSON Schema 的规则描述。
|
||||||
2. key 代表字段名,description 代表字段的描述,required 代表字段是否必须。
|
2. key 代表字段名;description 代表字段的描述;required 代表字段是否必须;enum 是可选值,代表可选的 value。
|
||||||
3. 如果字段内容为空,你可以返回空字符串。
|
3. 如果字段内容为空,你可以返回空字符串。
|
||||||
|
|
||||||
{{json}}
|
{{json}}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
|||||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant';
|
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||||
import { ModuleDataTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||||
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||||
|
|
||||||
let success = 0;
|
let success = 0;
|
||||||
@ -52,7 +52,7 @@ export async function initApp(limit = 50): Promise<any> {
|
|||||||
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: val
|
value: val
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
|||||||
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
|
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
|
||||||
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
|
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
import { FlowNodeInputTypeEnum, 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 { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||||
import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type.d';
|
import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type.d';
|
||||||
import { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api';
|
import { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api';
|
||||||
@ -317,7 +317,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
|||||||
key: ModuleInputKeyEnum.answerText,
|
key: ModuleInputKeyEnum.answerText,
|
||||||
value: formData.dataset.searchEmptyText,
|
value: formData.dataset.searchEmptyText,
|
||||||
type: FlowNodeInputTypeEnum.textarea,
|
type: FlowNodeInputTypeEnum.textarea,
|
||||||
valueType: ModuleDataTypeEnum.string,
|
valueType: ModuleIOValueTypeEnum.string,
|
||||||
label: '回复的内容',
|
label: '回复的内容',
|
||||||
connected: true
|
connected: true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,11 +6,10 @@ import { addLog } from '@fastgpt/service/common/system/log';
|
|||||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||||
import { findDatasetIdTreeByTopDatasetId } from '@fastgpt/service/core/dataset/controller';
|
import { findDatasetIdTreeByTopDatasetId } from '@fastgpt/service/core/dataset/controller';
|
||||||
import { Readable } from 'stream';
|
|
||||||
import type { Cursor } from '@fastgpt/service/common/mongo';
|
|
||||||
import { limitCheck } from './checkExportLimit';
|
import { limitCheck } from './checkExportLimit';
|
||||||
|
import { withNextCors } from '@fastgpt/service/common/middle/cors';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
let { datasetId } = req.query as {
|
let { datasetId } = req.query as {
|
||||||
@ -81,7 +80,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
error: err
|
error: err
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
})),
|
})),
|
||||||
...(global.communityPlugins?.map((plugin) => ({
|
...(global.communityPlugins?.map((plugin) => ({
|
||||||
id: plugin.id,
|
id: plugin.id,
|
||||||
templateType: ModuleTemplateTypeEnum.communityPlugin,
|
templateType: plugin.templateType ?? ModuleTemplateTypeEnum.other,
|
||||||
flowType: FlowNodeTypeEnum.pluginModule,
|
flowType: FlowNodeTypeEnum.pluginModule,
|
||||||
avatar: plugin.avatar,
|
avatar: plugin.avatar,
|
||||||
name: plugin.name,
|
name: plugin.name,
|
||||||
|
|||||||
69
projects/app/src/pages/api/plugins/TFSwitch/index.ts
Normal file
69
projects/app/src/pages/api/plugins/TFSwitch/index.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
|
||||||
|
type Props = HttpBodyType<{
|
||||||
|
input: string;
|
||||||
|
rule?: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: { input, rule = '' }
|
||||||
|
} = req.body as Props;
|
||||||
|
|
||||||
|
const result = (() => {
|
||||||
|
if (typeof input === 'string') {
|
||||||
|
const defaultReg: any[] = [
|
||||||
|
undefined,
|
||||||
|
'undefined',
|
||||||
|
null,
|
||||||
|
'null',
|
||||||
|
false,
|
||||||
|
'false',
|
||||||
|
0,
|
||||||
|
'0',
|
||||||
|
'none'
|
||||||
|
];
|
||||||
|
const customReg = rule.split('\n');
|
||||||
|
defaultReg.push(...customReg);
|
||||||
|
|
||||||
|
return !defaultReg.find((item) => {
|
||||||
|
const reg = typeof item === 'string' ? stringToRegex(item) : null;
|
||||||
|
if (reg) {
|
||||||
|
return reg.test(input);
|
||||||
|
}
|
||||||
|
return input === item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!input;
|
||||||
|
})();
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
...(result
|
||||||
|
? {
|
||||||
|
true: true
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
false: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).send(getErrText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToRegex(str: string) {
|
||||||
|
const regexFormat = /^\/(.+)\/([gimuy]*)$/;
|
||||||
|
const match = str.match(regexFormat);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const [, pattern, flags] = match;
|
||||||
|
return new RegExp(pattern, flags);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
projects/app/src/pages/api/plugins/textEditor/index.ts
Normal file
26
projects/app/src/pages/api/plugins/textEditor/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||||
|
|
||||||
|
type Props = HttpBodyType<{
|
||||||
|
text: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: { text, ...obj }
|
||||||
|
} = req.body as Props;
|
||||||
|
|
||||||
|
const textResult = replaceVariable(text, obj);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
text: textResult
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).send(getErrText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,9 +19,10 @@ import {
|
|||||||
} from '@fastgpt/global/core/ai/model';
|
} from '@fastgpt/global/core/ai/model';
|
||||||
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
|
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
|
||||||
import { getSimpleTemplatesFromPlus } from '@/service/core/app/utils';
|
import { getSimpleTemplatesFromPlus } from '@/service/core/app/utils';
|
||||||
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
import { getFastGPTFeConfig } from '@fastgpt/service/common/system/config/controller';
|
import { getFastGPTFeConfig } from '@fastgpt/service/common/system/config/controller';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
|
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
await getInitConfig();
|
await getInitConfig();
|
||||||
@ -251,12 +252,12 @@ function getSystemPlugin() {
|
|||||||
const filterFiles = files.filter((item) => item.endsWith('.json'));
|
const filterFiles = files.filter((item) => item.endsWith('.json'));
|
||||||
|
|
||||||
// read json file
|
// read json file
|
||||||
const fileTemplates = filterFiles.map((item) => {
|
const fileTemplates: PluginTemplateType[] = filterFiles.map((filename) => {
|
||||||
const content = readFileSync(`${basePath}/${item}`, 'utf-8');
|
const content = readFileSync(`${basePath}/${filename}`, 'utf-8');
|
||||||
return {
|
return {
|
||||||
id: `${PluginTypeEnum.community}-${item.replace('.json', '')}`,
|
...JSON.parse(content),
|
||||||
type: PluginTypeEnum.community,
|
id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`,
|
||||||
...JSON.parse(content)
|
source: PluginSourceEnum.community
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -138,6 +138,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
|
|
||||||
// openapi key
|
// openapi key
|
||||||
if (authType === AuthUserTypeEnum.apikey) {
|
if (authType === AuthUserTypeEnum.apikey) {
|
||||||
|
if (!apiKeyAppId) {
|
||||||
|
return Promise.reject(
|
||||||
|
'Key is error. You need to use the app key rather than the account key.'
|
||||||
|
);
|
||||||
|
}
|
||||||
const app = await MongoApp.findById(apiKeyAppId);
|
const app = await MongoApp.findById(apiKeyAppId);
|
||||||
|
|
||||||
if (!app) {
|
if (!app) {
|
||||||
|
|||||||
@ -27,7 +27,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
const { total } = pushReRankBill({
|
const { total } = pushReRankBill({
|
||||||
teamId,
|
teamId,
|
||||||
tmbId,
|
tmbId,
|
||||||
source: 'api'
|
source: 'api',
|
||||||
|
inputs
|
||||||
});
|
});
|
||||||
|
|
||||||
if (apikey) {
|
if (apikey) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user