mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
feat: add if elif (#6094)
This commit is contained in:
parent
ebba124c5c
commit
5a3e09518c
|
@ -5,10 +5,6 @@ from pydantic import BaseModel
|
||||||
from core.workflow.entities.base_node_data_entities import BaseNodeData
|
from core.workflow.entities.base_node_data_entities import BaseNodeData
|
||||||
|
|
||||||
|
|
||||||
class IfElseNodeData(BaseNodeData):
|
|
||||||
"""
|
|
||||||
Answer Node Data.
|
|
||||||
"""
|
|
||||||
class Condition(BaseModel):
|
class Condition(BaseModel):
|
||||||
"""
|
"""
|
||||||
Condition entity
|
Condition entity
|
||||||
|
@ -22,5 +18,21 @@ class IfElseNodeData(BaseNodeData):
|
||||||
]
|
]
|
||||||
value: Optional[str] = None
|
value: Optional[str] = None
|
||||||
|
|
||||||
logical_operator: Literal["and", "or"] = "and"
|
|
||||||
|
class IfElseNodeData(BaseNodeData):
|
||||||
|
"""
|
||||||
|
Answer Node Data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Case(BaseModel):
|
||||||
|
"""
|
||||||
|
Case entity representing a single logical condition group
|
||||||
|
"""
|
||||||
|
case_id: str
|
||||||
|
logical_operator: Literal["and", "or"]
|
||||||
conditions: list[Condition]
|
conditions: list[Condition]
|
||||||
|
|
||||||
|
logical_operator: Optional[Literal["and", "or"]] = "and"
|
||||||
|
conditions: Optional[list[Condition]] = None
|
||||||
|
|
||||||
|
cases: Optional[list[Case]] = None
|
||||||
|
|
|
@ -4,7 +4,8 @@ from core.workflow.entities.base_node_data_entities import BaseNodeData
|
||||||
from core.workflow.entities.node_entities import NodeRunResult, NodeType
|
from core.workflow.entities.node_entities import NodeRunResult, NodeType
|
||||||
from core.workflow.entities.variable_pool import VariablePool
|
from core.workflow.entities.variable_pool import VariablePool
|
||||||
from core.workflow.nodes.base_node import BaseNode
|
from core.workflow.nodes.base_node import BaseNode
|
||||||
from core.workflow.nodes.if_else.entities import IfElseNodeData
|
from core.workflow.nodes.if_else.entities import Condition, IfElseNodeData
|
||||||
|
from core.workflow.utils.variable_template_parser import VariableTemplateParser
|
||||||
from models.workflow import WorkflowNodeExecutionStatus
|
from models.workflow import WorkflowNodeExecutionStatus
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,68 +30,46 @@ class IfElseNode(BaseNode):
|
||||||
"condition_results": []
|
"condition_results": []
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
|
||||||
logical_operator = node_data.logical_operator
|
|
||||||
input_conditions = []
|
input_conditions = []
|
||||||
for condition in node_data.conditions:
|
final_result = False
|
||||||
actual_value = variable_pool.get_variable_value(
|
selected_case_id = None
|
||||||
variable_selector=condition.variable_selector
|
try:
|
||||||
|
# Check if the new cases structure is used
|
||||||
|
if node_data.cases:
|
||||||
|
for case in node_data.cases:
|
||||||
|
input_conditions, group_result = self.process_conditions(variable_pool, case.conditions)
|
||||||
|
# Apply the logical operator for the current case
|
||||||
|
final_result = all(group_result) if case.logical_operator == "and" else any(group_result)
|
||||||
|
|
||||||
|
process_datas["condition_results"].append(
|
||||||
|
{
|
||||||
|
"group": case.model_dump(),
|
||||||
|
"results": group_result,
|
||||||
|
"final_result": final_result,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_value = condition.value
|
# Break if a case passes (logical short-circuit)
|
||||||
|
if final_result:
|
||||||
|
selected_case_id = case.case_id # Capture the ID of the passing case
|
||||||
|
break
|
||||||
|
|
||||||
input_conditions.append({
|
else:
|
||||||
"actual_value": actual_value,
|
# Fallback to old structure if cases are not defined
|
||||||
"expected_value": expected_value,
|
input_conditions, group_result = self.process_conditions(variable_pool, node_data.conditions)
|
||||||
"comparison_operator": condition.comparison_operator
|
|
||||||
})
|
final_result = all(group_result) if node_data.logical_operator == "and" else any(group_result)
|
||||||
|
|
||||||
|
process_datas["condition_results"].append(
|
||||||
|
{
|
||||||
|
"group": "default",
|
||||||
|
"results": group_result,
|
||||||
|
"final_result": final_result
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
node_inputs["conditions"] = input_conditions
|
node_inputs["conditions"] = input_conditions
|
||||||
|
|
||||||
for input_condition in input_conditions:
|
|
||||||
actual_value = input_condition["actual_value"]
|
|
||||||
expected_value = input_condition["expected_value"]
|
|
||||||
comparison_operator = input_condition["comparison_operator"]
|
|
||||||
|
|
||||||
if comparison_operator == "contains":
|
|
||||||
compare_result = self._assert_contains(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "not contains":
|
|
||||||
compare_result = self._assert_not_contains(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "start with":
|
|
||||||
compare_result = self._assert_start_with(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "end with":
|
|
||||||
compare_result = self._assert_end_with(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "is":
|
|
||||||
compare_result = self._assert_is(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "is not":
|
|
||||||
compare_result = self._assert_is_not(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "empty":
|
|
||||||
compare_result = self._assert_empty(actual_value)
|
|
||||||
elif comparison_operator == "not empty":
|
|
||||||
compare_result = self._assert_not_empty(actual_value)
|
|
||||||
elif comparison_operator == "=":
|
|
||||||
compare_result = self._assert_equal(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "≠":
|
|
||||||
compare_result = self._assert_not_equal(actual_value, expected_value)
|
|
||||||
elif comparison_operator == ">":
|
|
||||||
compare_result = self._assert_greater_than(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "<":
|
|
||||||
compare_result = self._assert_less_than(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "≥":
|
|
||||||
compare_result = self._assert_greater_than_or_equal(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "≤":
|
|
||||||
compare_result = self._assert_less_than_or_equal(actual_value, expected_value)
|
|
||||||
elif comparison_operator == "null":
|
|
||||||
compare_result = self._assert_null(actual_value)
|
|
||||||
elif comparison_operator == "not null":
|
|
||||||
compare_result = self._assert_not_null(actual_value)
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
process_datas["condition_results"].append({
|
|
||||||
**input_condition,
|
|
||||||
"result": compare_result
|
|
||||||
})
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return NodeRunResult(
|
return NodeRunResult(
|
||||||
status=WorkflowNodeExecutionStatus.FAILED,
|
status=WorkflowNodeExecutionStatus.FAILED,
|
||||||
|
@ -99,21 +78,106 @@ class IfElseNode(BaseNode):
|
||||||
error=str(e)
|
error=str(e)
|
||||||
)
|
)
|
||||||
|
|
||||||
if logical_operator == "and":
|
outputs = {
|
||||||
compare_result = False not in [condition["result"] for condition in process_datas["condition_results"]]
|
"result": final_result
|
||||||
else:
|
}
|
||||||
compare_result = True in [condition["result"] for condition in process_datas["condition_results"]]
|
if node_data.cases:
|
||||||
|
outputs["selected_case_id"] = selected_case_id
|
||||||
|
|
||||||
return NodeRunResult(
|
data = NodeRunResult(
|
||||||
status=WorkflowNodeExecutionStatus.SUCCEEDED,
|
status=WorkflowNodeExecutionStatus.SUCCEEDED,
|
||||||
inputs=node_inputs,
|
inputs=node_inputs,
|
||||||
process_data=process_datas,
|
process_data=process_datas,
|
||||||
edge_source_handle="false" if not compare_result else "true",
|
edge_source_handle=selected_case_id if selected_case_id else "false", # Use case ID or 'default'
|
||||||
outputs={
|
outputs=outputs
|
||||||
"result": compare_result
|
)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def evaluate_condition(
|
||||||
|
self, actual_value: Optional[str | list], expected_value: str, comparison_operator: str
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Evaluate condition
|
||||||
|
:param actual_value: actual value
|
||||||
|
:param expected_value: expected value
|
||||||
|
:param comparison_operator: comparison operator
|
||||||
|
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
if comparison_operator == "contains":
|
||||||
|
return self._assert_contains(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "not contains":
|
||||||
|
return self._assert_not_contains(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "start with":
|
||||||
|
return self._assert_start_with(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "end with":
|
||||||
|
return self._assert_end_with(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "is":
|
||||||
|
return self._assert_is(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "is not":
|
||||||
|
return self._assert_is_not(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "empty":
|
||||||
|
return self._assert_empty(actual_value)
|
||||||
|
elif comparison_operator == "not empty":
|
||||||
|
return self._assert_not_empty(actual_value)
|
||||||
|
elif comparison_operator == "=":
|
||||||
|
return self._assert_equal(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "≠":
|
||||||
|
return self._assert_not_equal(actual_value, expected_value)
|
||||||
|
elif comparison_operator == ">":
|
||||||
|
return self._assert_greater_than(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "<":
|
||||||
|
return self._assert_less_than(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "≥":
|
||||||
|
return self._assert_greater_than_or_equal(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "≤":
|
||||||
|
return self._assert_less_than_or_equal(actual_value, expected_value)
|
||||||
|
elif comparison_operator == "null":
|
||||||
|
return self._assert_null(actual_value)
|
||||||
|
elif comparison_operator == "not null":
|
||||||
|
return self._assert_not_null(actual_value)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid comparison operator: {comparison_operator}")
|
||||||
|
|
||||||
|
def process_conditions(self, variable_pool: VariablePool, conditions: list[Condition]):
|
||||||
|
input_conditions = []
|
||||||
|
group_result = []
|
||||||
|
|
||||||
|
for condition in conditions:
|
||||||
|
actual_value = variable_pool.get_variable_value(
|
||||||
|
variable_selector=condition.variable_selector
|
||||||
|
)
|
||||||
|
|
||||||
|
if condition.value is not None:
|
||||||
|
variable_template_parser = VariableTemplateParser(template=condition.value)
|
||||||
|
expected_value = variable_template_parser.extract_variable_selectors()
|
||||||
|
variable_selectors = variable_template_parser.extract_variable_selectors()
|
||||||
|
if variable_selectors:
|
||||||
|
for variable_selector in variable_selectors:
|
||||||
|
value = variable_pool.get_variable_value(
|
||||||
|
variable_selector=variable_selector.value_selector
|
||||||
|
)
|
||||||
|
expected_value = variable_template_parser.format({variable_selector.variable: value})
|
||||||
|
else:
|
||||||
|
expected_value = condition.value
|
||||||
|
else:
|
||||||
|
expected_value = None
|
||||||
|
|
||||||
|
comparison_operator = condition.comparison_operator
|
||||||
|
input_conditions.append(
|
||||||
|
{
|
||||||
|
"actual_value": actual_value,
|
||||||
|
"expected_value": expected_value,
|
||||||
|
"comparison_operator": comparison_operator
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
result = self.evaluate_condition(actual_value, expected_value, comparison_operator)
|
||||||
|
group_result.append(result)
|
||||||
|
|
||||||
|
return input_conditions, group_result
|
||||||
|
|
||||||
def _assert_contains(self, actual_value: Optional[str | list], expected_value: str) -> bool:
|
def _assert_contains(self, actual_value: Optional[str | list], expected_value: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Assert contains
|
Assert contains
|
||||||
|
|
Loading…
Reference in New Issue
Block a user