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 <ericrhare@gmail.com>
This commit is contained in:
VICTOR CORREA GOMES 2024-12-16 15:13:25 -03:00 committed by GitHub
commit ef6226d25d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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