mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 20:37:48 +00:00
Concat textinput to input type (#2963)
* perf: toast position * concat textinput to input
This commit is contained in:
@@ -9,13 +9,16 @@ weight: 812
|
|||||||
|
|
||||||
## 更新说明
|
## 更新说明
|
||||||
|
|
||||||
1. 新增 - 全局变量支持数字类型,并且支持配置默认值和部分输入框参数。
|
1. 新增 - 全局变量支持数字类型,支持配置默认值和部分输入框参数。
|
||||||
2. 新增 - FE_DOMAIN 环境变量,配置该环境变量后,上传文件/图片会补全后缀后得到完整地址。(可解决 docx 文件图片链接,有时会无法被模型识别问题)
|
2. 新增 - 插件自定义输入,文本输入框、数字输入框、选择框、开关,默认都支持作为变量引用。
|
||||||
3. 新增 - 工具调用支持交互模式
|
3. 新增 - FE_DOMAIN 环境变量,配置该环境变量后,上传文件/图片会补全后缀后得到完整地址。(可解决 docx 文件图片链接,有时会无法被模型识别问题)
|
||||||
4. 新增 - Debug 模式支持输入全局变量
|
4. 新增 - 工具调用支持交互模式
|
||||||
5. 新增 - chat openapi 文档
|
5. 新增 - Debug 模式支持输入全局变量
|
||||||
6. 新增 - wiki 搜索插件
|
6. 新增 - chat OpenAPI 文档
|
||||||
7. 新增 - Cookie 隐私协议提示
|
7. 新增 - wiki 搜索插件
|
||||||
8. 修复 - 文件后缀判断,去除 query 影响。
|
8. 新增 - Google 搜索插件
|
||||||
9. 修复 - AI 响应为空时,会造成 LLM 历史记录合并。
|
9. 新增 - 数据库连接和操作插件
|
||||||
10. 修复 - 用户交互节点未阻塞流程。
|
10. 新增 - Cookie 隐私协议提示
|
||||||
|
11. 修复 - 文件后缀判断,去除 query 影响。
|
||||||
|
12. 修复 - AI 响应为空时,会造成 LLM 历史记录合并。
|
||||||
|
13. 修复 - 用户交互节点未阻塞流程。
|
||||||
|
@@ -267,7 +267,6 @@ export enum NodeOutputKeyEnum {
|
|||||||
export enum VariableInputEnum {
|
export enum VariableInputEnum {
|
||||||
input = 'input',
|
input = 'input',
|
||||||
textarea = 'textarea',
|
textarea = 'textarea',
|
||||||
textInput = 'textInput',
|
|
||||||
numberInput = 'numberInput',
|
numberInput = 'numberInput',
|
||||||
select = 'select',
|
select = 'select',
|
||||||
custom = 'custom'
|
custom = 'custom'
|
||||||
@@ -284,7 +283,7 @@ export const variableMap: Record<
|
|||||||
> = {
|
> = {
|
||||||
[VariableInputEnum.input]: {
|
[VariableInputEnum.input]: {
|
||||||
icon: 'core/workflow/inputType/input',
|
icon: 'core/workflow/inputType/input',
|
||||||
label: i18nT('common:core.workflow.inputType.input'),
|
label: i18nT('common:core.workflow.inputType.textInput'),
|
||||||
value: VariableInputEnum.input,
|
value: VariableInputEnum.input,
|
||||||
defaultValueType: WorkflowIOValueTypeEnum.string
|
defaultValueType: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
@@ -295,12 +294,6 @@ export const variableMap: Record<
|
|||||||
defaultValueType: WorkflowIOValueTypeEnum.string,
|
defaultValueType: WorkflowIOValueTypeEnum.string,
|
||||||
description: i18nT('app:variable.textarea_type_desc')
|
description: i18nT('app:variable.textarea_type_desc')
|
||||||
},
|
},
|
||||||
[VariableInputEnum.textInput]: {
|
|
||||||
icon: 'core/workflow/inputType/input',
|
|
||||||
label: i18nT('common:core.workflow.inputType.textInput'),
|
|
||||||
value: VariableInputEnum.textInput,
|
|
||||||
defaultValueType: WorkflowIOValueTypeEnum.string
|
|
||||||
},
|
|
||||||
[VariableInputEnum.numberInput]: {
|
[VariableInputEnum.numberInput]: {
|
||||||
icon: 'core/workflow/inputType/numberInput',
|
icon: 'core/workflow/inputType/numberInput',
|
||||||
label: i18nT('common:core.workflow.inputType.number input'),
|
label: i18nT('common:core.workflow.inputType.number input'),
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import { WorkflowIOValueTypeEnum } from '../constants';
|
import { WorkflowIOValueTypeEnum } from '../constants';
|
||||||
import { i18nT } from '../../../../web/i18n/utils';
|
import { i18nT } from '../../../../web/i18n/utils';
|
||||||
export enum FlowNodeInputTypeEnum { // render ui
|
export enum FlowNodeInputTypeEnum { // render ui
|
||||||
textInput = 'textInput',
|
|
||||||
reference = 'reference', // reference to other node output
|
reference = 'reference', // reference to other node output
|
||||||
|
input = 'input', // one line input
|
||||||
|
textarea = 'textarea',
|
||||||
numberInput = 'numberInput',
|
numberInput = 'numberInput',
|
||||||
switch = 'switch', // true/false
|
switch = 'switch', // true/false
|
||||||
select = 'select',
|
select = 'select',
|
||||||
@@ -26,11 +27,7 @@ export enum FlowNodeInputTypeEnum { // render ui
|
|||||||
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
|
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
|
||||||
|
|
||||||
hidden = 'hidden',
|
hidden = 'hidden',
|
||||||
custom = 'custom',
|
custom = 'custom'
|
||||||
|
|
||||||
// deprecated
|
|
||||||
input = 'input', // one line input
|
|
||||||
textarea = 'textarea'
|
|
||||||
}
|
}
|
||||||
export const FlowNodeInputMap: Record<
|
export const FlowNodeInputMap: Record<
|
||||||
FlowNodeInputTypeEnum,
|
FlowNodeInputTypeEnum,
|
||||||
@@ -38,9 +35,6 @@ export const FlowNodeInputMap: Record<
|
|||||||
icon: string;
|
icon: string;
|
||||||
}
|
}
|
||||||
> = {
|
> = {
|
||||||
[FlowNodeInputTypeEnum.textInput]: {
|
|
||||||
icon: 'core/workflow/inputType/input'
|
|
||||||
},
|
|
||||||
[FlowNodeInputTypeEnum.reference]: {
|
[FlowNodeInputTypeEnum.reference]: {
|
||||||
icon: 'core/workflow/inputType/reference'
|
icon: 'core/workflow/inputType/reference'
|
||||||
},
|
},
|
||||||
|
@@ -230,10 +230,6 @@ export const appData2FlowNodeIO = ({
|
|||||||
FlowNodeInputTypeEnum.textarea,
|
FlowNodeInputTypeEnum.textarea,
|
||||||
FlowNodeInputTypeEnum.reference
|
FlowNodeInputTypeEnum.reference
|
||||||
],
|
],
|
||||||
[VariableInputEnum.textInput]: [
|
|
||||||
FlowNodeInputTypeEnum.textInput,
|
|
||||||
FlowNodeInputTypeEnum.reference
|
|
||||||
],
|
|
||||||
[VariableInputEnum.numberInput]: [FlowNodeInputTypeEnum.numberInput],
|
[VariableInputEnum.numberInput]: [FlowNodeInputTypeEnum.numberInput],
|
||||||
[VariableInputEnum.select]: [FlowNodeInputTypeEnum.select],
|
[VariableInputEnum.select]: [FlowNodeInputTypeEnum.select],
|
||||||
[VariableInputEnum.custom]: [
|
[VariableInputEnum.custom]: [
|
||||||
|
@@ -60,11 +60,10 @@ const main = async ({
|
|||||||
// 使用类型断言来处理错误
|
// 使用类型断言来处理错误
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.error('Database query error:', error.message);
|
console.error('Database query error:', error.message);
|
||||||
throw new Error(error.message);
|
return Promise.reject(error.message);
|
||||||
} else {
|
|
||||||
console.error('Database query error:', error);
|
|
||||||
throw new Error('An unknown error occurred');
|
|
||||||
}
|
}
|
||||||
|
console.error('Database query error:', error);
|
||||||
|
return Promise.reject('An unknown error occurred');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -152,8 +152,8 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
} = await (async () => {
|
} = await (async () => {
|
||||||
const adaptMessages = chats2GPTMessages({
|
const adaptMessages = chats2GPTMessages({
|
||||||
messages,
|
messages,
|
||||||
reserveId: false,
|
reserveId: false
|
||||||
reserveTool: !!toolModel.toolChoice
|
// reserveTool: !!toolModel.toolChoice
|
||||||
});
|
});
|
||||||
|
|
||||||
if (toolModel.toolChoice) {
|
if (toolModel.toolChoice) {
|
||||||
|
@@ -36,11 +36,6 @@ const NodeInputSelect = ({
|
|||||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
|
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
|
||||||
title: t('common:core.workflow.inputType.Manual input')
|
title: t('common:core.workflow.inputType.Manual input')
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: FlowNodeInputTypeEnum.textInput,
|
|
||||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
|
|
||||||
title: t('common:core.workflow.inputType.Manual input')
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: FlowNodeInputTypeEnum.numberInput,
|
type: FlowNodeInputTypeEnum.numberInput,
|
||||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.numberInput].icon,
|
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.numberInput].icon,
|
||||||
|
@@ -36,7 +36,7 @@ export const defaultVariable: VariableItemType = {
|
|||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
key: '',
|
key: '',
|
||||||
label: '',
|
label: '',
|
||||||
type: VariableInputEnum.textInput,
|
type: VariableInputEnum.input,
|
||||||
description: '',
|
description: '',
|
||||||
required: true,
|
required: true,
|
||||||
valueType: WorkflowIOValueTypeEnum.string
|
valueType: WorkflowIOValueTypeEnum.string
|
||||||
@@ -73,10 +73,7 @@ const VariableEdit = ({
|
|||||||
const inputTypeList = useMemo(
|
const inputTypeList = useMemo(
|
||||||
() =>
|
() =>
|
||||||
Object.values(variableMap)
|
Object.values(variableMap)
|
||||||
.filter(
|
.filter((item) => item.value !== VariableInputEnum.textarea)
|
||||||
(item) =>
|
|
||||||
item.value !== VariableInputEnum.input && item.value !== VariableInputEnum.textarea
|
|
||||||
)
|
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
icon: item.icon,
|
icon: item.icon,
|
||||||
label: t(item.label as any),
|
label: t(item.label as any),
|
||||||
|
@@ -60,12 +60,13 @@ export const VariableInputItem = ({
|
|||||||
{item.description && <QuestionTip ml={1} label={item.description} />}
|
{item.description && <QuestionTip ml={1} label={item.description} />}
|
||||||
</Box>
|
</Box>
|
||||||
{item.type === VariableInputEnum.input && (
|
{item.type === VariableInputEnum.input && (
|
||||||
<Input
|
<PromptEditor
|
||||||
maxLength={item.maxLength || 4000}
|
value={item.defaultValue}
|
||||||
|
onChange={(e) => setValue(item.key, e)}
|
||||||
bg={'myGray.50'}
|
bg={'myGray.50'}
|
||||||
{...register(item.key, {
|
minH={40}
|
||||||
required: item.required
|
maxH={150}
|
||||||
})}
|
showOpenModal={false}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{item.type === VariableInputEnum.textarea && (
|
{item.type === VariableInputEnum.textarea && (
|
||||||
@@ -78,16 +79,7 @@ export const VariableInputItem = ({
|
|||||||
maxLength={item.maxLength || 4000}
|
maxLength={item.maxLength || 4000}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{item.type === VariableInputEnum.textInput && (
|
|
||||||
<PromptEditor
|
|
||||||
value={item.defaultValue}
|
|
||||||
onChange={(e) => setValue(item.key, e)}
|
|
||||||
bg={'myGray.50'}
|
|
||||||
minH={50}
|
|
||||||
maxH={150}
|
|
||||||
showOpenModal={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === VariableInputEnum.select && (
|
{item.type === VariableInputEnum.select && (
|
||||||
<Controller
|
<Controller
|
||||||
key={item.key}
|
key={item.key}
|
||||||
|
@@ -221,13 +221,12 @@ const RenderUserFormInteractive = React.memo(function RenderFormInput({
|
|||||||
{input.description && <QuestionTip ml={1} label={input.description} />}
|
{input.description && <QuestionTip ml={1} label={input.description} />}
|
||||||
</Flex>
|
</Flex>
|
||||||
{input.type === FlowNodeInputTypeEnum.input && (
|
{input.type === FlowNodeInputTypeEnum.input && (
|
||||||
<Input
|
<PromptEditor
|
||||||
bg={'white'}
|
value={input.value}
|
||||||
maxLength={input.maxLength}
|
onChange={(e) => setValue(input.label, e)}
|
||||||
isDisabled={interactive.params.submitted}
|
minH={40}
|
||||||
{...register(input.label, {
|
maxH={100}
|
||||||
required: input.required
|
showOpenModal={false}
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{input.type === FlowNodeInputTypeEnum.textarea && (
|
{input.type === FlowNodeInputTypeEnum.textarea && (
|
||||||
@@ -241,15 +240,6 @@ const RenderUserFormInteractive = React.memo(function RenderFormInput({
|
|||||||
maxLength={input.maxLength || 4000}
|
maxLength={input.maxLength || 4000}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{input.type === FlowNodeInputTypeEnum.textInput && (
|
|
||||||
<PromptEditor
|
|
||||||
value={input.value}
|
|
||||||
onChange={(e) => setValue(input.label, e)}
|
|
||||||
minH={40}
|
|
||||||
maxH={100}
|
|
||||||
showOpenModal={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{input.type === FlowNodeInputTypeEnum.numberInput && (
|
{input.type === FlowNodeInputTypeEnum.numberInput && (
|
||||||
<NumberInput
|
<NumberInput
|
||||||
step={1}
|
step={1}
|
||||||
|
@@ -27,7 +27,7 @@ const SaveButton = ({
|
|||||||
const [isSave, setIsSave] = useState(false);
|
const [isSave, setIsSave] = useState(false);
|
||||||
const { toast } = useToast({
|
const { toast } = useToast({
|
||||||
containerStyle: {
|
containerStyle: {
|
||||||
mt: 20,
|
mt: '60px',
|
||||||
fontSize: 'sm'
|
fontSize: 'sm'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -22,7 +22,7 @@ const SaveAndPublishModal = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast({
|
const { toast } = useToast({
|
||||||
containerStyle: {
|
containerStyle: {
|
||||||
mt: 20,
|
mt: '60px',
|
||||||
fontSize: 'sm'
|
fontSize: 'sm'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -11,7 +11,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
|
|||||||
import InputTypeConfig from '../NodePluginIO/InputTypeConfig';
|
import InputTypeConfig from '../NodePluginIO/InputTypeConfig';
|
||||||
|
|
||||||
export const defaultFormInput: UserInputFormItemType = {
|
export const defaultFormInput: UserInputFormItemType = {
|
||||||
type: FlowNodeInputTypeEnum.textInput,
|
type: FlowNodeInputTypeEnum.input,
|
||||||
key: '',
|
key: '',
|
||||||
label: '',
|
label: '',
|
||||||
description: '',
|
description: '',
|
||||||
@@ -55,7 +55,7 @@ const InputFormEditModal = ({
|
|||||||
{
|
{
|
||||||
icon: 'core/workflow/inputType/input',
|
icon: 'core/workflow/inputType/input',
|
||||||
label: t('common:core.workflow.inputType.textInput'),
|
label: t('common:core.workflow.inputType.textInput'),
|
||||||
value: FlowNodeInputTypeEnum.textInput,
|
value: FlowNodeInputTypeEnum.input,
|
||||||
defaultValueType: WorkflowIOValueTypeEnum.string
|
defaultValueType: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -55,7 +55,7 @@ const FieldEditModal = ({
|
|||||||
{
|
{
|
||||||
icon: 'core/workflow/inputType/input',
|
icon: 'core/workflow/inputType/input',
|
||||||
label: t('common:core.workflow.inputType.textInput'),
|
label: t('common:core.workflow.inputType.textInput'),
|
||||||
value: FlowNodeInputTypeEnum.textInput,
|
value: FlowNodeInputTypeEnum.input,
|
||||||
defaultValueType: WorkflowIOValueTypeEnum.string
|
defaultValueType: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -137,7 +137,7 @@ const InputTypeConfig = ({
|
|||||||
}, [inputType]);
|
}, [inputType]);
|
||||||
|
|
||||||
const showMaxLenInput = useMemo(() => {
|
const showMaxLenInput = useMemo(() => {
|
||||||
const list = [FlowNodeInputTypeEnum.textInput];
|
const list = [FlowNodeInputTypeEnum.input];
|
||||||
return list.includes(inputType as FlowNodeInputTypeEnum);
|
return list.includes(inputType as FlowNodeInputTypeEnum);
|
||||||
}, [inputType]);
|
}, [inputType]);
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ const InputTypeConfig = ({
|
|||||||
|
|
||||||
const showDefaultValue = useMemo(() => {
|
const showDefaultValue = useMemo(() => {
|
||||||
const list = [
|
const list = [
|
||||||
FlowNodeInputTypeEnum.textInput,
|
FlowNodeInputTypeEnum.input,
|
||||||
FlowNodeInputTypeEnum.JSONEditor,
|
FlowNodeInputTypeEnum.JSONEditor,
|
||||||
FlowNodeInputTypeEnum.numberInput,
|
FlowNodeInputTypeEnum.numberInput,
|
||||||
FlowNodeInputTypeEnum.switch,
|
FlowNodeInputTypeEnum.switch,
|
||||||
@@ -323,7 +323,7 @@ const InputTypeConfig = ({
|
|||||||
</NumberInputStepper>
|
</NumberInputStepper>
|
||||||
</NumberInput>
|
</NumberInput>
|
||||||
)}
|
)}
|
||||||
{inputType === FlowNodeInputTypeEnum.textInput && (
|
{inputType === FlowNodeInputTypeEnum.input && (
|
||||||
<PromptEditor
|
<PromptEditor
|
||||||
value={defaultValue}
|
value={defaultValue}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
@@ -28,10 +28,6 @@ const RenderList: {
|
|||||||
types: [FlowNodeInputTypeEnum.switch],
|
types: [FlowNodeInputTypeEnum.switch],
|
||||||
Component: dynamic(() => import('./templates/Switch'))
|
Component: dynamic(() => import('./templates/Switch'))
|
||||||
},
|
},
|
||||||
{
|
|
||||||
types: [FlowNodeInputTypeEnum.textInput],
|
|
||||||
Component: dynamic(() => import('./templates/TextInput'))
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
types: [FlowNodeInputTypeEnum.selectApp],
|
types: [FlowNodeInputTypeEnum.selectApp],
|
||||||
Component: dynamic(() => import('./templates/SelectApp'))
|
Component: dynamic(() => import('./templates/SelectApp'))
|
||||||
|
@@ -10,9 +10,7 @@ import { getEditorVariables } from '../../../../../utils';
|
|||||||
|
|
||||||
const TextInputRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
const TextInputRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
const { nodeList, edges, onChangeNode } = useContextSelector(WorkflowContext, (v) => v);
|
||||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
|
||||||
|
|
||||||
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
||||||
|
|
||||||
@@ -51,7 +49,7 @@ const TextInputRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
|||||||
maxLength={item.maxLength}
|
maxLength={item.maxLength}
|
||||||
minH={40}
|
minH={40}
|
||||||
maxH={120}
|
maxH={120}
|
||||||
placeholder={t((item.placeholder as any) || '')}
|
placeholder={t(item.placeholder as any)}
|
||||||
value={item.value}
|
value={item.value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
isFlow={true}
|
isFlow={true}
|
||||||
|
Reference in New Issue
Block a user