From 861bbd29ca9ff3cb8f99759f9b53596298553de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Thu, 28 May 2026 10:28:52 +0800 Subject: [PATCH] feat: 1) support `length_not_equal` comparison; 2) All length comparators support numbers; 3) Optimize the `is_true` and `is_not_true` comparisons --- apps/application/flow/compare/__init__.py | 6 ++-- apps/application/flow/compare/is_not_true.py | 7 ++-- apps/application/flow/compare/is_true.py | 9 ++--- .../flow/compare/len_equal_compare.py | 36 +++++++++++++++++-- .../flow/compare/len_ge_compare.py | 9 +++-- .../flow/compare/len_gt_compare.py | 9 +++-- .../flow/compare/len_le_compare.py | 9 +++-- .../flow/compare/len_lt_compare.py | 9 +++-- .../flow/compare/len_not_equal_compare.py | 23 ++++++++++++ .../application/flow/compare/regex_compare.py | 2 +- .../flow/compare/wildcard_compare.py | 10 +++--- ui/src/locales/lang/en-US/workflow.ts | 5 +-- ui/src/locales/lang/zh-CN/workflow.ts | 5 +-- ui/src/locales/lang/zh-Hant/workflow.ts | 5 +-- ui/src/workflow/common/data.ts | 5 +-- 15 files changed, 111 insertions(+), 38 deletions(-) create mode 100644 apps/application/flow/compare/len_not_equal_compare.py diff --git a/apps/application/flow/compare/__init__.py b/apps/application/flow/compare/__init__.py index ce0c430e1ad..93ab64c9c8b 100644 --- a/apps/application/flow/compare/__init__.py +++ b/apps/application/flow/compare/__init__.py @@ -23,6 +23,7 @@ from .len_gt_compare import LenGTCompare from .len_le_compare import LenLECompare from .len_lt_compare import LenLTCompare +from .len_not_equal_compare import LenNotEqualCompare from .lt_compare import LTCompare from .not_contain_compare import NotContainCompare from .not_equal_compare import NotEqualCompare @@ -35,6 +36,8 @@ 'is_not_null': IsNotNullCompare(), 'contain': ContainCompare(), 'not_contain': NotContainCompare(), + 'regex': RegexCompare(), + 'wildcard': WildcardCompare(), 'eq': EqualCompare(), 'not_eq': NotEqualCompare(), 'ge': GECompare(), @@ -42,6 +45,7 @@ 'le': LECompare(), 'lt': LTCompare(), 'len_eq': LenEqualCompare(), + 'len_not_eq': LenNotEqualCompare(), 'len_ge': LenGECompare(), 'len_gt': LenGTCompare(), 'len_le': LenLECompare(), @@ -50,8 +54,6 @@ 'is_not_true': IsNotTrueCompare(), 'start_with': StartWithCompare(), 'end_with': EndWithCompare(), - 'regex': RegexCompare(), - 'wildcard': WildcardCompare(), } diff --git a/apps/application/flow/compare/is_not_true.py b/apps/application/flow/compare/is_not_true.py index fabeec2cc41..4fc649bb9dd 100644 --- a/apps/application/flow/compare/is_not_true.py +++ b/apps/application/flow/compare/is_not_true.py @@ -4,7 +4,7 @@ @Author:虎 @file: is_not_true.py @date:2025/4/7 13:44 - @desc: + @desc: 不为真比较器 """ from .compare import Compare @@ -12,7 +12,4 @@ class IsNotTrueCompare(Compare): def compare(self, source_value, compare, target_value): - try: - return source_value is False - except Exception: - return False + return source_value not in (True, 'True', 'true', 1, '1') diff --git a/apps/application/flow/compare/is_true.py b/apps/application/flow/compare/is_true.py index 8cb4a45a2a5..4d962268f05 100644 --- a/apps/application/flow/compare/is_true.py +++ b/apps/application/flow/compare/is_true.py @@ -2,9 +2,9 @@ """ @project: MaxKB @Author:虎 - @file: IsTrue.py + @file: is_true.py @date:2025/4/7 13:38 - @desc: + @desc: 为真比较器 """ from .compare import Compare @@ -12,7 +12,4 @@ class IsTrueCompare(Compare): def compare(self, source_value, compare, target_value): - try: - return source_value is True - except Exception: - return False + return source_value in (True, 'True', 'true', 1, '1') diff --git a/apps/application/flow/compare/len_equal_compare.py b/apps/application/flow/compare/len_equal_compare.py index 98a5314a292..7479c5128ba 100644 --- a/apps/application/flow/compare/len_equal_compare.py +++ b/apps/application/flow/compare/len_equal_compare.py @@ -4,15 +4,45 @@ @Author:虎 @file: equal_compare.py @date:2024/6/7 14:44 - @desc: + @desc: 长度等于比较器 """ from .compare import Compare +def compute_length(source_value, target_length) -> list: + """ + 计算长度 + + Args: + source_value: 引用变量 + target_length: 目标长度字符串 + + Raises: + ValueError: 当 target_value 不是数字 或 小于0时,抛出该异常 + """ + # 获取target_value的长度 + target_length = int(target_length) if target_length else 0 + if target_length < 0: + raise ValueError("The target length must be greater than or equal to 0") + + # 获取source_value的长度 + try: + source_length = len(source_value) if source_value is not None else 0 + except Exception: + # 可计算数字长度 + source_length = len(str(source_value)) + + return [source_length, target_length] + + class LenEqualCompare(Compare): def compare(self, source_value, compare, target_value): try: - return len(source_value) == int(target_value) - except Exception as e: + # 计算长度 + source_length, target_length = compute_length(source_value, target_value) + + # 长度等于 比较 + return source_length == target_length + except Exception: return False diff --git a/apps/application/flow/compare/len_ge_compare.py b/apps/application/flow/compare/len_ge_compare.py index 06dd566cf24..41227d2efa7 100644 --- a/apps/application/flow/compare/len_ge_compare.py +++ b/apps/application/flow/compare/len_ge_compare.py @@ -4,15 +4,20 @@ @Author:虎 @file: lt_compare.py @date:2024/6/11 9:52 - @desc: 大于比较器 + @desc: 长度大于等于比较器 """ from .compare import Compare +from .len_equal_compare import compute_length class LenGECompare(Compare): def compare(self, source_value, compare, target_value): try: - return len(source_value) >= int(target_value) + # 计算长度 + source_length, target_length = compute_length(source_value, target_value) + + # 长度大于等于 比较 + return source_length >= target_length except Exception: return False diff --git a/apps/application/flow/compare/len_gt_compare.py b/apps/application/flow/compare/len_gt_compare.py index fae2668e0ba..c11c3eb9b86 100644 --- a/apps/application/flow/compare/len_gt_compare.py +++ b/apps/application/flow/compare/len_gt_compare.py @@ -4,15 +4,20 @@ @Author:虎 @file: lt_compare.py @date:2024/6/11 9:52 - @desc: 大于比较器 + @desc: 长度大于比较器 """ from .compare import Compare +from .len_equal_compare import compute_length class LenGTCompare(Compare): def compare(self, source_value, compare, target_value): try: - return len(source_value) > int(target_value) + # 计算长度 + source_length, target_length = compute_length(source_value, target_value) + + # 长度大于 比较 + return source_length > target_length except Exception: return False diff --git a/apps/application/flow/compare/len_le_compare.py b/apps/application/flow/compare/len_le_compare.py index 41b9ee9f709..0a7bef1a441 100644 --- a/apps/application/flow/compare/len_le_compare.py +++ b/apps/application/flow/compare/len_le_compare.py @@ -4,15 +4,20 @@ @Author:虎 @file: lt_compare.py @date:2024/6/11 9:52 - @desc: 小于比较器 + @desc: 长度小于等于比较器 """ from .compare import Compare +from .len_equal_compare import compute_length class LenLECompare(Compare): def compare(self, source_value, compare, target_value): try: - return len(source_value) <= int(target_value) + # 计算长度 + source_length, target_length = compute_length(source_value, target_value) + + # 长度小于等于 比较 + return source_length <= target_length except Exception: return False diff --git a/apps/application/flow/compare/len_lt_compare.py b/apps/application/flow/compare/len_lt_compare.py index 4a9b11654ca..0871d167464 100644 --- a/apps/application/flow/compare/len_lt_compare.py +++ b/apps/application/flow/compare/len_lt_compare.py @@ -4,15 +4,20 @@ @Author:虎 @file: lt_compare.py @date:2024/6/11 9:52 - @desc: 小于比较器 + @desc: 长度小于比较器 """ from .compare import Compare +from .len_equal_compare import compute_length class LenLTCompare(Compare): def compare(self, source_value, compare, target_value): try: - return len(source_value) < int(target_value) + # 计算长度 + source_length, target_length = compute_length(source_value, target_value) + + # 长度小于 比较 + return source_length < target_length except Exception: return False diff --git a/apps/application/flow/compare/len_not_equal_compare.py b/apps/application/flow/compare/len_not_equal_compare.py new file mode 100644 index 00000000000..75c7231b031 --- /dev/null +++ b/apps/application/flow/compare/len_not_equal_compare.py @@ -0,0 +1,23 @@ +# coding=utf-8 +""" +@project: maxkb +@Author: wangliang181230 +@file: len_not_equal_compare.py +@date: 2026/4/28 20:17 +@desc: 长度不等于比较器 +""" +from .compare import Compare +from .len_equal_compare import compute_length + + +class LenNotEqualCompare(Compare): + + def compare(self, source_value, compare, target_value): + try: + # 计算长度 + source_length, target_length = compute_length(source_value, target_value) + + # 长度不等于 比较 + return source_length != target_length + except Exception: + return False diff --git a/apps/application/flow/compare/regex_compare.py b/apps/application/flow/compare/regex_compare.py index 613300e6589..23f16fbb364 100644 --- a/apps/application/flow/compare/regex_compare.py +++ b/apps/application/flow/compare/regex_compare.py @@ -23,7 +23,7 @@ def compile_and_cache(regex): match = match_cache.get(regex) if not match: - match = re.compile(regex).fullmatch + match = re.compile(regex, flags=re.DOTALL).fullmatch match_cache.set(regex, match) return match diff --git a/apps/application/flow/compare/wildcard_compare.py b/apps/application/flow/compare/wildcard_compare.py index 43c903a9360..6e6462051bb 100644 --- a/apps/application/flow/compare/wildcard_compare.py +++ b/apps/application/flow/compare/wildcard_compare.py @@ -12,12 +12,11 @@ from .compare import Compare from common.cache.mem_cache import MemCache - match_cache = MemCache('wildcard_to_regex', { - 'TIMEOUT': 3600, # 缓存有效期为 1 小时 + 'TIMEOUT': 3600, # 缓存有效期为 1 小时 'OPTIONS': { - 'MAX_ENTRIES': 500, # 最多缓存 500 个条目 - 'CULL_FREQUENCY': 10, # 达到上限时,删除约 1/10 的缓存 + 'MAX_ENTRIES': 500, # 最多缓存 500 个条目 + 'CULL_FREQUENCY': 10, # 达到上限时,删除约 1/10 的缓存 }, }) @@ -26,10 +25,11 @@ def translate_and_compile_and_cache(wildcard): match = match_cache.get(wildcard) if not match: regex = fnmatch.translate(wildcard) - match = re.compile(regex).match + match = re.compile(regex, flags=re.DOTALL).fullmatch match_cache.set(wildcard, match) return match + class WildcardCompare(Compare): def compare(self, source_value, compare, target_value): diff --git a/ui/src/locales/lang/en-US/workflow.ts b/ui/src/locales/lang/en-US/workflow.ts index f322667c8a3..af244af1aae 100644 --- a/ui/src/locales/lang/en-US/workflow.ts +++ b/ui/src/locales/lang/en-US/workflow.ts @@ -537,6 +537,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', @@ -544,14 +546,13 @@ You are a master of problem optimization, adept at accurately inferring user int le: 'Less than or equal to', lt: 'Less than', len_eq: 'Length equal to', + len_not_eq: 'Length not equal to', len_ge: 'Length greater than or equal to', len_gt: 'Length greater than', len_le: 'Length less than or equal to', len_lt: 'Length less than', is_true: 'Is true', is_not_true: 'Is not true', - regex: 'Regex matching', - wildcard: 'Wildcard matching', }, 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..a87ee5c40f1 100644 --- a/ui/src/locales/lang/zh-CN/workflow.ts +++ b/ui/src/locales/lang/zh-CN/workflow.ts @@ -528,6 +528,8 @@ export default { is_not_null: '不为空', contain: '包含', not_contain: '不包含', + regex: '正则匹配', + wildcard: '通配符匹配', eq: '等于', not_eq: '不等于', ge: '大于等于', @@ -535,14 +537,13 @@ export default { le: '小于等于', lt: '小于', len_eq: '长度等于', + len_not_eq: '长度不等于', len_ge: '长度大于等于', len_gt: '长度大于', len_le: '长度小于等于', len_lt: '长度小于', is_true: '为真', is_not_true: '不为真', - regex: '正则匹配', - wildcard: '通配符匹配', }, SystemPromptPlaceholder: '系统提示词,可以引用系统中的变量:如', UserPromptPlaceholder: '用户提示词,可以引用系统中的变量:如', diff --git a/ui/src/locales/lang/zh-Hant/workflow.ts b/ui/src/locales/lang/zh-Hant/workflow.ts index 6678d4536a7..eeecf494c35 100644 --- a/ui/src/locales/lang/zh-Hant/workflow.ts +++ b/ui/src/locales/lang/zh-Hant/workflow.ts @@ -522,6 +522,8 @@ export default { is_not_null: '不為空', contain: '包含', not_contain: '不包含', + regex: '正則匹配', + wildcard: '通配符匹配', eq: '等於', not_eq: '不等於', ge: '大於等於', @@ -529,14 +531,13 @@ export default { le: '小於等於', lt: '小於', len_eq: '長度等於', + len_not_eq: '長度不等於', len_ge: '長度大於等於', len_gt: '長度大於', len_le: '長度小於等於', len_lt: '長度小於', is_true: '為真', is_not_true: '不為真', - regex: '正則匹配', - wildcard: '通配符匹配', }, SystemPromptPlaceholder: '系統提示詞,可以引用系統中的變量:如', UserPromptPlaceholder: '用戶提示詞,可以引用系統中的變量:如', diff --git a/ui/src/workflow/common/data.ts b/ui/src/workflow/common/data.ts index 23fe80e60e2..80520694f3e 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') }, @@ -1132,6 +1134,7 @@ export const compareList = [ { value: 'le', label: t('workflow.compare.le') }, { value: 'lt', label: t('workflow.compare.lt') }, { value: 'len_eq', label: t('workflow.compare.len_eq') }, + { value: 'len_not_eq', label: t('workflow.compare.len_not_eq') }, { value: 'len_ge', label: t('workflow.compare.len_ge') }, { value: 'len_gt', label: t('workflow.compare.len_gt') }, { value: 'len_le', label: t('workflow.compare.len_le') }, @@ -1140,8 +1143,6 @@ export const compareList = [ { value: 'is_not_true', label: t('workflow.compare.is_not_true') }, { 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,