mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-15 07:31:19 +00:00
4.6.8 supplement (#831)
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
2
packages/global/core/chat/type.d.ts
vendored
2
packages/global/core/chat/type.d.ts
vendored
@@ -121,7 +121,9 @@ export type moduleDispatchResType = {
|
||||
extractResult?: Record<string, any>;
|
||||
|
||||
// http
|
||||
params?: Record<string, any>;
|
||||
body?: Record<string, any>;
|
||||
headers?: Record<string, any>;
|
||||
httpResult?: Record<string, any>;
|
||||
|
||||
// plugin output
|
||||
|
9
packages/global/core/module/api.d.ts
vendored
9
packages/global/core/module/api.d.ts
vendored
@@ -1,14 +1,11 @@
|
||||
import { VectorModelItemType } from '../ai/model.d';
|
||||
import { DYNAMIC_INPUT_KEY } from './constants';
|
||||
|
||||
export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[];
|
||||
|
||||
export type HttpBodyType<T = any> = {
|
||||
appId: string;
|
||||
chatId?: string;
|
||||
responseChatItemId?: string;
|
||||
variables: Record<string, any>;
|
||||
data: T;
|
||||
};
|
||||
[DYNAMIC_INPUT_KEY]: Record<string, any>;
|
||||
} & T;
|
||||
export type HttpQueryType = {
|
||||
appId: string;
|
||||
chatId?: string;
|
||||
|
@@ -74,8 +74,10 @@ export enum ModuleInputKeyEnum {
|
||||
|
||||
// http
|
||||
httpReqUrl = 'system_httpReqUrl',
|
||||
httpHeader = 'system_httpHeader',
|
||||
httpHeaders = 'system_httpHeader',
|
||||
httpMethod = 'system_httpMethod',
|
||||
httpParams = 'system_httpParams',
|
||||
httpJsonBody = 'system_httpJsonBody',
|
||||
abandon_httpUrl = 'url',
|
||||
|
||||
// app
|
||||
|
@@ -53,6 +53,7 @@ export enum FlowNodeTypeEnum {
|
||||
classifyQuestion = 'classifyQuestion',
|
||||
contentExtract = 'contentExtract',
|
||||
httpRequest = 'httpRequest',
|
||||
httpRequest468 = 'httpRequest468',
|
||||
runApp = 'app',
|
||||
pluginModule = 'pluginModule',
|
||||
pluginInput = 'pluginInput',
|
||||
|
@@ -2,15 +2,19 @@ import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '../../node/constant';
|
||||
import { FlowModuleTemplateType } from '../../type';
|
||||
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleTemplateTypeEnum } from '../../constants';
|
||||
} 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';
|
||||
} from '../../input';
|
||||
import { Output_Template_AddOutput, Output_Template_Finish } from '../../output';
|
||||
|
||||
export const HttpModule: FlowModuleTemplateType = {
|
||||
id: FlowNodeTypeEnum.httpRequest,
|
||||
@@ -18,7 +22,8 @@ export const HttpModule: FlowModuleTemplateType = {
|
||||
flowType: FlowNodeTypeEnum.httpRequest,
|
||||
avatar: '/imgs/module/http.png',
|
||||
name: 'core.module.template.Http request',
|
||||
intro: 'core.module.template.Http request intro',
|
||||
intro:
|
||||
'该Http模块已被弃用,将于2024/3/31 不再提供服务。请尽快删除该模块并重新添加新的 Http 模块。',
|
||||
showStatus: true,
|
||||
inputs: [
|
||||
Input_Template_Switch,
|
||||
@@ -54,9 +59,10 @@ export const HttpModule: FlowModuleTemplateType = {
|
||||
showTargetInPlugin: false
|
||||
},
|
||||
{
|
||||
key: ModuleInputKeyEnum.httpHeader,
|
||||
key: ModuleInputKeyEnum.httpHeaders,
|
||||
type: FlowNodeInputTypeEnum.JSONEditor,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
value: '',
|
||||
label: 'core.module.input.label.Http Request Header',
|
||||
description: 'core.module.input.description.Http Request Header',
|
||||
placeholder: 'core.module.input.description.Http Request Header',
|
@@ -23,7 +23,7 @@ export const AiCFR: FlowModuleTemplateType = {
|
||||
flowType: FlowNodeTypeEnum.cfr,
|
||||
avatar: '/imgs/module/cfr.svg',
|
||||
name: 'core.module.template.Query extension',
|
||||
intro: '该模块已合并到知识库搜索参数中,无需单独使用。',
|
||||
intro: '该模块已合并到知识库搜索参数中,无需单独使用。模块将于2024/3/31弃用,请尽快修改。',
|
||||
showStatus: true,
|
||||
inputs: [
|
||||
Input_Template_Switch,
|
||||
|
122
packages/global/core/module/template/system/http468.ts
Normal file
122
packages/global/core/module/template/system/http468.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '../../node/constant';
|
||||
import { FlowModuleTemplateType } from '../../type';
|
||||
import {
|
||||
DYNAMIC_INPUT_KEY,
|
||||
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 HttpModule468: FlowModuleTemplateType = {
|
||||
id: FlowNodeTypeEnum.httpRequest468,
|
||||
templateType: ModuleTemplateTypeEnum.externalCall,
|
||||
flowType: FlowNodeTypeEnum.httpRequest468,
|
||||
avatar: '/imgs/module/http.png',
|
||||
name: 'core.module.template.Http request',
|
||||
intro: 'core.module.template.Http request intro',
|
||||
showStatus: true,
|
||||
inputs: [
|
||||
Input_Template_Switch,
|
||||
{
|
||||
key: ModuleInputKeyEnum.httpMethod,
|
||||
type: FlowNodeInputTypeEnum.custom,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
label: '',
|
||||
value: 'POST',
|
||||
required: true,
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false
|
||||
},
|
||||
{
|
||||
key: ModuleInputKeyEnum.httpReqUrl,
|
||||
type: FlowNodeInputTypeEnum.hidden,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
label: '',
|
||||
description: 'core.module.input.description.Http Request Url',
|
||||
placeholder: 'https://api.ai.com/getInventory',
|
||||
required: false,
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false
|
||||
},
|
||||
{
|
||||
key: ModuleInputKeyEnum.httpHeaders,
|
||||
type: FlowNodeInputTypeEnum.custom,
|
||||
valueType: ModuleIOValueTypeEnum.any,
|
||||
value: [],
|
||||
label: '',
|
||||
description: 'core.module.input.description.Http Request Header',
|
||||
placeholder: 'core.module.input.description.Http Request Header',
|
||||
required: false,
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false
|
||||
},
|
||||
{
|
||||
key: ModuleInputKeyEnum.httpParams,
|
||||
type: FlowNodeInputTypeEnum.hidden,
|
||||
valueType: ModuleIOValueTypeEnum.any,
|
||||
value: [],
|
||||
label: '',
|
||||
required: false,
|
||||
showTargetInApp: false,
|
||||
showTargetInPlugin: false
|
||||
},
|
||||
{
|
||||
key: ModuleInputKeyEnum.httpJsonBody,
|
||||
type: FlowNodeInputTypeEnum.hidden,
|
||||
valueType: ModuleIOValueTypeEnum.any,
|
||||
value: '',
|
||||
label: '',
|
||||
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,
|
||||
{
|
||||
...Output_Template_AddOutput,
|
||||
editField: {
|
||||
key: true,
|
||||
name: true,
|
||||
description: true,
|
||||
dataType: true
|
||||
},
|
||||
defaultEditField: {
|
||||
label: '',
|
||||
key: '',
|
||||
description: '',
|
||||
outputType: FlowNodeOutputTypeEnum.source,
|
||||
valueType: ModuleIOValueTypeEnum.string
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
@@ -6,7 +6,6 @@ export const RunPluginModule: FlowModuleTemplateType = {
|
||||
id: FlowNodeTypeEnum.pluginModule,
|
||||
templateType: ModuleTemplateTypeEnum.externalCall,
|
||||
flowType: FlowNodeTypeEnum.pluginModule,
|
||||
avatar: '',
|
||||
intro: '',
|
||||
name: '',
|
||||
showStatus: false,
|
||||
|
@@ -1,6 +1,7 @@
|
||||
export enum sseResponseEventEnum {
|
||||
error = 'error',
|
||||
answer = 'answer',
|
||||
answer = 'answer', // animation stream
|
||||
response = 'response', // direct response, not animation
|
||||
moduleStatus = 'moduleStatus',
|
||||
appStreamResponse = 'appStreamResponse' // sse response request
|
||||
}
|
||||
|
@@ -1,17 +1,20 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import Editor, { loader, useMonaco } from '@monaco-editor/react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import React, { useEffect, useCallback, useRef, useState } from 'react';
|
||||
import Editor, { Monaco, loader, useMonaco } from '@monaco-editor/react';
|
||||
import { Box, BoxProps } from '@chakra-ui/react';
|
||||
import MyIcon from '../../Icon';
|
||||
import { EditorVariablePickerType } from '../PromptEditor/type';
|
||||
import { useToast } from '../../../../hooks/useToast';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
loader.config({
|
||||
paths: { vs: 'https://cdn.staticfile.net/monaco-editor/0.43.0/min/vs' }
|
||||
paths: { vs: '/js/monaco-editor.0.45.0/vs' }
|
||||
});
|
||||
|
||||
type Props = Omit<BoxProps, 'onChange' | 'resize' | 'height'> & {
|
||||
type EditorVariablePickerType = {
|
||||
key: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
type Props = Omit<BoxProps, 'resize' | 'onChange'> & {
|
||||
height?: number;
|
||||
resize?: boolean;
|
||||
defaultValue?: string;
|
||||
@@ -42,43 +45,95 @@ const options = {
|
||||
tabSize: 2
|
||||
};
|
||||
|
||||
const JSONEditor = ({ defaultValue, value, onChange, resize, variables, ...props }: Props) => {
|
||||
const JSONEditor = ({ defaultValue, value, onChange, resize, variables = [], ...props }: Props) => {
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const [height, setHeight] = useState(props.height || 100);
|
||||
const initialY = useRef(0);
|
||||
const completionRegisterRef = useRef<any>();
|
||||
const monaco = useMonaco();
|
||||
const triggerChar = useRef<string>();
|
||||
|
||||
useEffect(() => {
|
||||
completionRegisterRef.current = monaco?.languages.registerCompletionItemProvider('json', {
|
||||
triggerCharacters: ['"'],
|
||||
provideCompletionItems: function (model, position) {
|
||||
var word = model.getWordUntilPosition(position);
|
||||
var range = {
|
||||
if (!monaco) return;
|
||||
|
||||
// 自定义补全提供者
|
||||
completionRegisterRef.current = monaco.languages.registerCompletionItemProvider('json', {
|
||||
triggerCharacters: ['{'],
|
||||
provideCompletionItems: function (model, position, context) {
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
|
||||
if (context.triggerCharacter) {
|
||||
console.log(context.triggerCharacter);
|
||||
triggerChar.current = context.triggerCharacter;
|
||||
}
|
||||
const word = model.getWordUntilPosition(position);
|
||||
const range = {
|
||||
startLineNumber: position.lineNumber,
|
||||
endLineNumber: position.lineNumber,
|
||||
startColumn: word.startColumn,
|
||||
endColumn: word.endColumn
|
||||
};
|
||||
|
||||
const startText = lineContent.substring(0, position.column - 1); // 光标前的文本
|
||||
const endText = lineContent.substring(position.column - 1); // 光标后的文本
|
||||
const before2Char = startText[startText.length - 2];
|
||||
const beforeChar = startText[startText.length - 1];
|
||||
const afterChar = endText[0];
|
||||
const after2Char = endText[1];
|
||||
|
||||
if (before2Char !== '{' && beforeChar !== '"') {
|
||||
return {
|
||||
suggestions: []
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
suggestions:
|
||||
variables?.map((item) => ({
|
||||
label: `${item.label}`,
|
||||
kind: monaco.languages.CompletionItemKind.Function,
|
||||
documentation: item.label,
|
||||
insertText: `{{${item.label}}}`,
|
||||
range: range
|
||||
})) || [],
|
||||
dispose: () => {}
|
||||
variables?.map((item) => {
|
||||
let insertText = item.key;
|
||||
if (before2Char !== '{') {
|
||||
insertText = `{${insertText}`;
|
||||
}
|
||||
if (afterChar !== '}') {
|
||||
insertText = `${insertText}}`;
|
||||
}
|
||||
if (after2Char !== '}') {
|
||||
insertText = `${insertText}}`;
|
||||
}
|
||||
|
||||
return {
|
||||
label: item.key,
|
||||
kind: monaco.languages.CompletionItemKind.Variable,
|
||||
detail: item.label,
|
||||
insertText: insertText,
|
||||
range
|
||||
};
|
||||
}) || []
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 自定义语法高亮
|
||||
monaco.languages.setMonarchTokensProvider('json', {
|
||||
tokenizer: {
|
||||
root: [
|
||||
// 匹配variables里的变量
|
||||
[new RegExp(`{{(${variables.map((item) => item.key).join('|')})}}`), 'variable'],
|
||||
[/".*?"/, 'string'], // 匹配字符串
|
||||
[/[{}\[\]]/, '@brackets'], // 匹配括号
|
||||
[/[0-9]+/, 'number'], // 匹配数字
|
||||
[/true|false/, 'keyword'], // 匹配布尔值
|
||||
[/:/, 'delimiter'], // 匹配冒号
|
||||
[/,/, 'delimiter.comma'] // 匹配逗号
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
completionRegisterRef.current?.dispose();
|
||||
};
|
||||
}, [monaco, completionRegisterRef.current]);
|
||||
}, [monaco, variables]);
|
||||
|
||||
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
initialY.current = e.clientY;
|
||||
@@ -98,6 +153,48 @@ const JSONEditor = ({ defaultValue, value, onChange, resize, variables, ...props
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
}, []);
|
||||
|
||||
const onBlur = useCallback(() => {
|
||||
if (!value) return;
|
||||
// replace {{xx}} to true
|
||||
const replaceValue = value?.replace(/{{(.*?)}}/g, 'true');
|
||||
try {
|
||||
JSON.parse(replaceValue);
|
||||
} catch (error) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: t('common.jsonEditor.Parse error')
|
||||
});
|
||||
}
|
||||
}, [value]);
|
||||
const beforeMount = useCallback((monaco: Monaco) => {
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||
validate: false,
|
||||
allowComments: false,
|
||||
schemas: [
|
||||
{
|
||||
uri: 'http://myserver/foo-schema.json', // 一个假设的 URI
|
||||
fileMatch: ['*'], // 匹配所有文件
|
||||
schema: {} // 空的 Schema
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
monaco.editor.defineTheme('JSONEditorTheme', {
|
||||
base: 'vs', // 可以基于已有的主题进行定制
|
||||
inherit: true, // 继承基础主题的设置
|
||||
rules: [{ token: 'variable', foreground: '2B5FD9' }],
|
||||
colors: {
|
||||
'editor.background': '#ffffff00',
|
||||
'editorLineNumber.foreground': '#aaa',
|
||||
'editorOverviewRuler.border': '#ffffff00',
|
||||
'editor.lineHighlightBackground': '#F7F8FA',
|
||||
'scrollbarSlider.background': '#E8EAEC',
|
||||
'editorIndentGuide.activeBackground': '#ddd',
|
||||
'editorIndentGuide.background': '#eee'
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box position={'relative'}>
|
||||
{resize && (
|
||||
@@ -105,7 +202,7 @@ const JSONEditor = ({ defaultValue, value, onChange, resize, variables, ...props
|
||||
position={'absolute'}
|
||||
right={'0'}
|
||||
bottom={'0'}
|
||||
zIndex={999}
|
||||
zIndex={10}
|
||||
cursor={'ns-resize'}
|
||||
px={'4px'}
|
||||
onMouseDown={handleMouseDown}
|
||||
@@ -119,47 +216,20 @@ const JSONEditor = ({ defaultValue, value, onChange, resize, variables, ...props
|
||||
borderRadius={'md'}
|
||||
borderColor={'myGray.200'}
|
||||
py={2}
|
||||
{...props}
|
||||
height={'auto'}
|
||||
{...props}
|
||||
>
|
||||
<Editor
|
||||
height={height}
|
||||
defaultLanguage="json"
|
||||
options={options as any}
|
||||
theme={'JSONEditorTheme'}
|
||||
beforeMount={(monaco) => {
|
||||
monaco?.editor.defineTheme('JSONEditorTheme', {
|
||||
base: 'vs',
|
||||
inherit: true,
|
||||
rules: [],
|
||||
colors: {
|
||||
'editor.background': '#ffffff00',
|
||||
'editorLineNumber.foreground': '#aaa',
|
||||
'editorOverviewRuler.border': '#ffffff00',
|
||||
'editor.lineHighlightBackground': '#F7F8FA',
|
||||
'scrollbarSlider.background': '#E8EAEC',
|
||||
'editorIndentGuide.activeBackground': '#ddd',
|
||||
'editorIndentGuide.background': '#eee'
|
||||
}
|
||||
});
|
||||
}}
|
||||
theme="JSONEditorTheme"
|
||||
beforeMount={beforeMount}
|
||||
defaultValue={defaultValue}
|
||||
value={value}
|
||||
onChange={(e) => onChange?.(e || '')}
|
||||
wrapperProps={{
|
||||
onBlur: () => {
|
||||
if (!value) return;
|
||||
try {
|
||||
JSON.parse(value as string);
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: t('common.Invalid Json'),
|
||||
description: error.message,
|
||||
status: 'warning',
|
||||
isClosable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
onBlur
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
@@ -10,6 +10,7 @@ import { useCallback, useTransition } from 'react';
|
||||
|
||||
const PromptEditor = ({
|
||||
showOpenModal = true,
|
||||
showResize = true,
|
||||
variables = [],
|
||||
value,
|
||||
onChange,
|
||||
@@ -19,6 +20,7 @@ const PromptEditor = ({
|
||||
title
|
||||
}: {
|
||||
showOpenModal?: boolean;
|
||||
showResize?: boolean;
|
||||
variables?: EditorVariablePickerType[];
|
||||
value?: string;
|
||||
onChange?: (text: string) => void;
|
||||
@@ -48,7 +50,7 @@ const PromptEditor = ({
|
||||
return (
|
||||
<>
|
||||
<Editor
|
||||
showResize
|
||||
showResize={showResize}
|
||||
showOpenModal={showOpenModal}
|
||||
onOpenModal={onOpen}
|
||||
variables={variables}
|
||||
|
@@ -100,7 +100,7 @@ export default function VariablePickerPlugin({
|
||||
p={2}
|
||||
borderRadius={'md'}
|
||||
position={'fixed'}
|
||||
w={'200px'}
|
||||
w={'auto'}
|
||||
overflow={'hidden'}
|
||||
zIndex={99999}
|
||||
>
|
||||
@@ -113,6 +113,8 @@ export default function VariablePickerPlugin({
|
||||
py={2}
|
||||
borderRadius={'sm'}
|
||||
cursor={'pointer'}
|
||||
maxH={'300px'}
|
||||
overflow={'auto'}
|
||||
_notLast={{
|
||||
mb: 2
|
||||
}}
|
||||
@@ -133,8 +135,11 @@ export default function VariablePickerPlugin({
|
||||
setHighlightedIndex(index);
|
||||
}}
|
||||
>
|
||||
<MyIcon name={item.icon as any} w={'14px'} />
|
||||
<Box ml={2} fontSize={'sm'}>{`${item.key}(${item.label})`}</Box>
|
||||
<MyIcon name={(item.icon as any) || 'core/modules/variable'} w={'14px'} />
|
||||
<Box ml={2} fontSize={'sm'}>
|
||||
{item.key}
|
||||
{item.key !== item.label && `(${item.label})`}
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Box>,
|
||||
|
Reference in New Issue
Block a user