From ef6226d25dfb01f4e1ebe80a2fe242fc47297cda Mon Sep 17 00:00:00 2001 From: VICTOR CORREA GOMES <112295415+Vigtu@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:13:25 -0300 Subject: [PATCH] feat: Enhance ConditionalRouterComponent with Regex Matching and UI Improvements (#5217) * fix: revert response return type to Message for compatibility * Change the max_iterations and case_sensitive advanced options * feat: add regex matching and real-time refresh functionality * Refactor evaluate_condition method to use elif statements for clarity - Changed if statements to elif in the evaluate_condition method to improve readability and indicate mutually exclusive conditions. - Removed redundant advanced=True line from BoolInput for case sensitivity. * [autofix.ci] apply automated fixes * Format code using make format - Applied code formatting to ensure consistency and adherence to style guidelines. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Hare --- .../components/logic/conditional_router.py | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/backend/base/langflow/components/logic/conditional_router.py b/src/backend/base/langflow/components/logic/conditional_router.py index f8a166c2b..80c2739a6 100644 --- a/src/backend/base/langflow/components/logic/conditional_router.py +++ b/src/backend/base/langflow/components/logic/conditional_router.py @@ -1,3 +1,5 @@ +import re + from langflow.custom import Component from langflow.io import BoolInput, DropdownInput, IntInput, MessageInput, MessageTextInput, Output from langflow.schema.message import Message @@ -27,16 +29,16 @@ class ConditionalRouterComponent(Component): DropdownInput( name="operator", display_name="Operator", - options=["equals", "not equals", "contains", "starts with", "ends with"], + options=["equals", "not equals", "contains", "starts with", "ends with", "matches regex"], info="The operator to apply for comparing the texts.", value="equals", + real_time_refresh=True, ), BoolInput( name="case_sensitive", display_name="Case Sensitive", info="If true, the comparison will be case sensitive.", value=False, - advanced=True, ), MessageInput( name="message", @@ -49,6 +51,7 @@ class ConditionalRouterComponent(Component): display_name="Max Iterations", info="The maximum number of iterations for the conditional router.", value=10, + advanced=True, ), DropdownInput( name="default_route", @@ -69,7 +72,7 @@ class ConditionalRouterComponent(Component): self.__iteration_updated = False def evaluate_condition(self, input_text: str, match_text: str, operator: str, *, case_sensitive: bool) -> bool: - if not case_sensitive: + if not case_sensitive and operator != "matches regex": input_text = input_text.lower() match_text = match_text.lower() @@ -83,6 +86,11 @@ class ConditionalRouterComponent(Component): return input_text.startswith(match_text) if operator == "ends with": return input_text.endswith(match_text) + if operator == "matches regex": + try: + return bool(re.match(match_text, input_text)) + except re.error: + return False # Return False if the regex is invalid return False def iterate_and_stop_once(self, route_to_stop: str): @@ -90,11 +98,10 @@ class ConditionalRouterComponent(Component): self.update_ctx({f"{self._id}_iteration": self.ctx.get(f"{self._id}_iteration", 0) + 1}) self.__iteration_updated = True if self.ctx.get(f"{self._id}_iteration", 0) >= self.max_iterations and route_to_stop == self.default_route: - # We need to stop the other route route_to_stop = "true_result" if route_to_stop == "false_result" else "false_result" self.stop(route_to_stop) - def true_response(self) -> Message | str: + def true_response(self) -> Message: result = self.evaluate_condition( self.input_text, self.match_text, self.operator, case_sensitive=self.case_sensitive ) @@ -103,9 +110,9 @@ class ConditionalRouterComponent(Component): self.iterate_and_stop_once("false_result") return self.message self.iterate_and_stop_once("true_result") - return "" + return Message(content="") - def false_response(self) -> Message | str: + def false_response(self) -> Message: result = self.evaluate_condition( self.input_text, self.match_text, self.operator, case_sensitive=self.case_sensitive ) @@ -114,4 +121,18 @@ class ConditionalRouterComponent(Component): self.iterate_and_stop_once("true_result") return self.message self.iterate_and_stop_once("false_result") - return "" + return Message(content="") + + def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict: + if field_name == "operator": + if field_value == "matches regex": + if "case_sensitive" in build_config: + del build_config["case_sensitive"] + # Ensure case_sensitive is present for all other operators + elif "case_sensitive" not in build_config: + case_sensitive_input = next( + (input_field for input_field in self.inputs if input_field.name == "case_sensitive"), None + ) + if case_sensitive_input: + build_config["case_sensitive"] = case_sensitive_input.to_dict() + return build_config