From 471cd4aefe8562387d13f28476465c4e92dc4323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Wed, 3 Jun 2026 17:30:38 +0800 Subject: [PATCH] feat: Supports `type_is` and `type_not` comparisons --- apps/application/flow/compare/__init__.py | 8 +++++-- .../flow/compare/type_is_compare.py | 23 +++++++++++++++++++ .../flow/compare/type_not_compare.py | 23 +++++++++++++++++++ ui/src/locales/lang/en-US/workflow.ts | 9 ++++++-- ui/src/locales/lang/zh-CN/workflow.ts | 9 ++++++-- ui/src/locales/lang/zh-Hant/workflow.ts | 9 ++++++-- ui/src/workflow/common/data.ts | 12 ++++++---- .../workflow/nodes/condition-node/index.vue | 20 +++++++++++++--- .../workflow/nodes/loop-break-node/index.vue | 16 +++++++++++++ .../nodes/loop-continue-node/index.vue | 16 +++++++++++++ 10 files changed, 130 insertions(+), 15 deletions(-) create mode 100644 apps/application/flow/compare/type_is_compare.py create mode 100644 apps/application/flow/compare/type_not_compare.py diff --git a/apps/application/flow/compare/__init__.py b/apps/application/flow/compare/__init__.py index ce0c430e1ad..e681859019b 100644 --- a/apps/application/flow/compare/__init__.py +++ b/apps/application/flow/compare/__init__.py @@ -28,6 +28,8 @@ from .not_equal_compare import NotEqualCompare from .regex_compare import RegexCompare from .start_with import StartWithCompare +from .type_is_compare import TypeIsCompare +from .type_not_compare import TypeNotCompare from .wildcard_compare import WildcardCompare _compare_handler_dict = { @@ -35,6 +37,8 @@ 'is_not_null': IsNotNullCompare(), 'contain': ContainCompare(), 'not_contain': NotContainCompare(), + 'regex': RegexCompare(), + 'wildcard': WildcardCompare(), 'eq': EqualCompare(), 'not_eq': NotEqualCompare(), 'ge': GECompare(), @@ -48,10 +52,10 @@ 'len_lt': LenLTCompare(), 'is_true': IsTrueCompare(), 'is_not_true': IsNotTrueCompare(), + 'type_is': TypeIsCompare(), + 'type_not': TypeNotCompare(), 'start_with': StartWithCompare(), 'end_with': EndWithCompare(), - 'regex': RegexCompare(), - 'wildcard': WildcardCompare(), } diff --git a/apps/application/flow/compare/type_is_compare.py b/apps/application/flow/compare/type_is_compare.py new file mode 100644 index 00000000000..199f477f70c --- /dev/null +++ b/apps/application/flow/compare/type_is_compare.py @@ -0,0 +1,23 @@ +# coding=utf-8 +""" +@project: MaxKB +@Author:wangliang181230 +@file:type_is_compare.py +@date:2026/5/25 10:01 +@desc: “数据类型是” 比较器 +""" +from .compare import Compare + + +class TypeIsCompare(Compare): + + def compare(self, source_value, compare, target_value): + try: + if target_value == "json": + return isinstance(source_value, (list, dict)) + elif target_value == "num": + return isinstance(source_value, (int, float)) + else: + return type(source_value).__name__ == target_value + except Exception: + return False diff --git a/apps/application/flow/compare/type_not_compare.py b/apps/application/flow/compare/type_not_compare.py new file mode 100644 index 00000000000..634cf057b96 --- /dev/null +++ b/apps/application/flow/compare/type_not_compare.py @@ -0,0 +1,23 @@ +# coding=utf-8 +""" +@project: MaxKB +@Author:wangliang181230 +@file:type_not_compare.py +@date:2026/5/25 10:01 +@desc: “数据类型不是” 比较器 +""" +from .compare import Compare + + +class TypeNotCompare(Compare): + + def compare(self, source_value, compare, target_value): + try: + if target_value == "json": + return not isinstance(source_value, (list, dict)) + elif target_value == "num": + return not isinstance(source_value, (int, float)) + else: + return type(source_value).__name__ != target_value + except Exception: + return False diff --git a/ui/src/locales/lang/en-US/workflow.ts b/ui/src/locales/lang/en-US/workflow.ts index f322667c8a3..d60c799fa7f 100644 --- a/ui/src/locales/lang/en-US/workflow.ts +++ b/ui/src/locales/lang/en-US/workflow.ts @@ -235,6 +235,9 @@ You are a master of problem optimization, adept at accurately inferring user int requiredMessage: 'Please select conditions', }, valueMessage: 'Please enter a value', + verify_type_compare: { + requiredMessage: 'Please select a type', + }, addCondition: 'Add Condition', addBranch: 'Add Branch', }, @@ -537,6 +540,8 @@ You are a master of problem optimization, adept at accurately inferring user int is_not_null: 'Is not null', contain: 'Contains', not_contain: 'Does not contain', + regex: 'Regex matching', + wildcard: 'Wildcard matching', eq: 'Equal to', not_eq: 'Not equal to', ge: 'Greater than or equal to', @@ -550,8 +555,8 @@ You are a master of problem optimization, adept at accurately inferring user int len_lt: 'Length less than', is_true: 'Is true', is_not_true: 'Is not true', - regex: 'Regex matching', - wildcard: 'Wildcard matching', + type_is: 'Type is', + type_not: 'Type not', }, SystemPromptPlaceholder: 'System Prompt, can reference variables in the system, such as', UserPromptPlaceholder: 'User Prompt, can reference variables in the system, such as', diff --git a/ui/src/locales/lang/zh-CN/workflow.ts b/ui/src/locales/lang/zh-CN/workflow.ts index 42cdf5a89f7..1aa3cb222e2 100644 --- a/ui/src/locales/lang/zh-CN/workflow.ts +++ b/ui/src/locales/lang/zh-CN/workflow.ts @@ -235,6 +235,9 @@ export default { requiredMessage: '请选择条件', }, valueMessage: '请输入值', + verify_type_compare: { + requiredMessage: '请选择类型', + }, addCondition: '添加条件', addBranch: '添加分支', }, @@ -528,6 +531,8 @@ export default { is_not_null: '不为空', contain: '包含', not_contain: '不包含', + regex: '正则匹配', + wildcard: '通配符匹配', eq: '等于', not_eq: '不等于', ge: '大于等于', @@ -541,8 +546,8 @@ export default { len_lt: '长度小于', is_true: '为真', is_not_true: '不为真', - regex: '正则匹配', - wildcard: '通配符匹配', + type_is: '类型是', + type_not: '类型不是', }, SystemPromptPlaceholder: '系统提示词,可以引用系统中的变量:如', UserPromptPlaceholder: '用户提示词,可以引用系统中的变量:如', diff --git a/ui/src/locales/lang/zh-Hant/workflow.ts b/ui/src/locales/lang/zh-Hant/workflow.ts index 6678d4536a7..0c19626e228 100644 --- a/ui/src/locales/lang/zh-Hant/workflow.ts +++ b/ui/src/locales/lang/zh-Hant/workflow.ts @@ -235,6 +235,9 @@ export default { requiredMessage: '請選擇條件', }, valueMessage: '請輸入值', + verify_type_compare: { + requiredMessage: '請選擇類型', + }, addCondition: '添加條件', addBranch: '添加分支', }, @@ -522,6 +525,8 @@ export default { is_not_null: '不為空', contain: '包含', not_contain: '不包含', + regex: '正則匹配', + wildcard: '通配符匹配', eq: '等於', not_eq: '不等於', ge: '大於等於', @@ -535,8 +540,8 @@ export default { len_lt: '長度小於', is_true: '為真', is_not_true: '不為真', - regex: '正則匹配', - wildcard: '通配符匹配', + type_is: '類型是', + type_not: '類型不是', }, SystemPromptPlaceholder: '系統提示詞,可以引用系統中的變量:如', UserPromptPlaceholder: '用戶提示詞,可以引用系統中的變量:如', diff --git a/ui/src/workflow/common/data.ts b/ui/src/workflow/common/data.ts index 23fe80e60e2..cb56d833151 100644 --- a/ui/src/workflow/common/data.ts +++ b/ui/src/workflow/common/data.ts @@ -1125,6 +1125,8 @@ export const compareList = [ { value: 'is_not_null', label: t('workflow.compare.is_not_null') }, { value: 'contain', label: t('workflow.compare.contain') }, { value: 'not_contain', label: t('workflow.compare.not_contain') }, + { value: 'regex', label: t('workflow.compare.regex') }, + { value: 'wildcard', label: t('workflow.compare.wildcard') }, { value: 'eq', label: t('workflow.compare.eq') }, { value: 'not_eq', label: t('workflow.compare.not_eq') }, { value: 'ge', label: t('workflow.compare.ge') }, @@ -1138,10 +1140,10 @@ export const compareList = [ { value: 'len_lt', label: t('workflow.compare.len_lt') }, { value: 'is_true', label: t('workflow.compare.is_true') }, { value: 'is_not_true', label: t('workflow.compare.is_not_true') }, + { value: 'type_is', label: t('workflow.compare.type_is') }, + { value: 'type_not', label: t('workflow.compare.type_not') }, { value: 'start_with', label: 'startWith' }, { value: 'end_with', label: 'endWith' }, - { value: 'regex', label: t('workflow.compare.regex') }, - { value: 'wildcard', label: t('workflow.compare.wildcard') }, ] export const nodeDict: any = { [WorkflowType.AiChat]: aiChatNode, @@ -1533,6 +1535,8 @@ ${t('workflow.nodes.formNode.form_content_format2')}`, 'workflow.compare.is_not_null', 'workflow.compare.contain', 'workflow.compare.not_contain', + 'workflow.compare.regex', + 'workflow.compare.wildcard', 'workflow.compare.eq', 'workflow.compare.not_eq', 'workflow.compare.ge', @@ -1546,9 +1550,9 @@ ${t('workflow.nodes.formNode.form_content_format2')}`, 'workflow.compare.len_lt', 'workflow.compare.is_true', 'workflow.compare.is_not_true', + 'workflow.compare.type_is', + 'workflow.compare.type_not', ].forEach((key, index) => defineLocaleGetter(compareList[index], 'label', key)) -defineLocaleGetter(compareList[19], 'label', 'workflow.compare.regex') -defineLocaleGetter(compareList[20], 'label', 'workflow.compare.wildcard') export function isWorkFlow(type: string | undefined) { return type === 'WORK_FLOW' diff --git a/ui/src/workflow/nodes/condition-node/index.vue b/ui/src/workflow/nodes/condition-node/index.vue index d80c2c28cad..922aeb7692f 100644 --- a/ui/src/workflow/nodes/condition-node/index.vue +++ b/ui/src/workflow/nodes/condition-node/index.vue @@ -115,11 +115,25 @@ trigger: 'blur', }" > + + + + + + + + + + + diff --git a/ui/src/workflow/nodes/loop-break-node/index.vue b/ui/src/workflow/nodes/loop-break-node/index.vue index d718dca4bc5..66b182374f1 100644 --- a/ui/src/workflow/nodes/loop-break-node/index.vue +++ b/ui/src/workflow/nodes/loop-break-node/index.vue @@ -83,7 +83,23 @@ trigger: 'blur', }" > + + + + + + + + + + + diff --git a/ui/src/workflow/nodes/loop-continue-node/index.vue b/ui/src/workflow/nodes/loop-continue-node/index.vue index d718dca4bc5..66b182374f1 100644 --- a/ui/src/workflow/nodes/loop-continue-node/index.vue +++ b/ui/src/workflow/nodes/loop-continue-node/index.vue @@ -83,7 +83,23 @@ trigger: 'blur', }" > + + + + + + + + + + +