diff --git a/apps/application/flow/compare/__init__.py b/apps/application/flow/compare/__init__.py index f0dd01523f5..4e99bfa7270 100644 --- a/apps/application/flow/compare/__init__.py +++ b/apps/application/flow/compare/__init__.py @@ -25,10 +25,12 @@ from .lt_compare import * from .not_contain_compare import * from .not_equal_compare import * +from .regex_compare import RegexCompare from .start_with import StartWithCompare +from .wildcard_compare import WildcardCompare compare_handle_list = [GECompare(), GTCompare(), ContainCompare(), EqualCompare(), LTCompare(), LECompare(), LenLECompare(), LenGECompare(), LenEqualCompare(), LenGTCompare(), LenLTCompare(), IsNullCompare(), IsNotNullCompare(), NotContainCompare(), NotEqualCompare(), IsTrueCompare(), IsNotTrueCompare(), StartWithCompare(), - EndWithCompare()] + EndWithCompare(), RegexCompare(), WildcardCompare()] diff --git a/apps/application/flow/compare/regex_compare.py b/apps/application/flow/compare/regex_compare.py new file mode 100644 index 00000000000..8fd98f3eca8 --- /dev/null +++ b/apps/application/flow/compare/regex_compare.py @@ -0,0 +1,40 @@ +# coding=utf-8 +""" + @project: maxkb + @Author:wangliang181230 + @file: regex_compare.py + @date:2026/3/30 12:11 + @desc: +""" +import re +from typing import List + +from application.flow.compare import Compare +from common.cache.mem_cache import MemCache + + +match_cache = MemCache('regex', { + 'TIMEOUT': 3600, # 缓存有效期为 1 小时 + 'OPTIONS': { + 'MAX_ENTRIES': 500, # 最多缓存 500 个条目 + 'CULL_FREQUENCY': 10, # 达到上限时,删除约 1/10 的缓存 + }, +}) + + +def compile_and_cache(regex): + match = match_cache.get(regex) + if not match: + match = re.compile(regex).match + match_cache.set(regex, match) + return match + +class RegexCompare(Compare): + + def support(self, node_id, fields: List[str], source_value, compare, target_value): + if compare == 'regex': + return True + + def compare(self, source_value, compare, target_value): + match = compile_and_cache(str(target_value)) + return bool(match(str(source_value))) diff --git a/apps/application/flow/compare/wildcard_compare.py b/apps/application/flow/compare/wildcard_compare.py new file mode 100644 index 00000000000..65ea2c74a5a --- /dev/null +++ b/apps/application/flow/compare/wildcard_compare.py @@ -0,0 +1,43 @@ +# coding=utf-8 +""" + @project: maxkb + @Author:wangliang181230 + @file: wildcard_compare.py + @date:2026/3/30 12:11 + @desc: +""" +import fnmatch +import re +from typing import List + +from application.flow.compare import Compare +from common.cache.mem_cache import MemCache + + +match_cache = MemCache('wildcard_to_regex', { + 'TIMEOUT': 3600, # 缓存有效期为 1 小时 + 'OPTIONS': { + 'MAX_ENTRIES': 500, # 最多缓存 500 个条目 + 'CULL_FREQUENCY': 10, # 达到上限时,删除约 1/10 的缓存 + }, +}) + + +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_cache.set(wildcard, match) + return match + +class WildcardCompare(Compare): + + def support(self, node_id, fields: List[str], source_value, compare, target_value): + if compare == 'wildcard': + return True + + def compare(self, source_value, compare, target_value): + # 转成正则,性能更高 + match = translate_and_compile_and_cache(str(target_value)) + return bool(match(str(source_value))) diff --git a/ui/src/locales/lang/en-US/workflow.ts b/ui/src/locales/lang/en-US/workflow.ts index d4268a6f242..f87956b3f7a 100644 --- a/ui/src/locales/lang/en-US/workflow.ts +++ b/ui/src/locales/lang/en-US/workflow.ts @@ -538,6 +538,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', }, 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 cdb243d9d6a..3e9a5d8a7d8 100644 --- a/ui/src/locales/lang/zh-CN/workflow.ts +++ b/ui/src/locales/lang/zh-CN/workflow.ts @@ -529,6 +529,8 @@ export default { 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 51ceadff86a..8d482d1f2b6 100644 --- a/ui/src/locales/lang/zh-Hant/workflow.ts +++ b/ui/src/locales/lang/zh-Hant/workflow.ts @@ -523,6 +523,8 @@ export default { 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 46ac1fb1b83..12d4e813b37 100644 --- a/ui/src/workflow/common/data.ts +++ b/ui/src/workflow/common/data.ts @@ -1098,6 +1098,8 @@ 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,