Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions apps/application/flow/step_node/loop_node/impl/base_loop_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ def handler(self, workflow):
class BaseLoopNode(ILoopNode):
def save_context(self, details, workflow_manage):
self.context['result'] = details.get('result')
for key, value in details['context'].items():
if key not in self.context:
self.context[key] = value
self.answer_text = str(details.get('result'))

def get_answer_list(self) -> List[Answer] | None:
Expand Down Expand Up @@ -262,7 +265,13 @@ def workflow_manage_new_instance(loop_data, global_data, start_node_id=None,
_write_context=get_write_context(loop_type, array, number, loop_body, stream),
_is_interrupt=_is_interrupt_exec)

def get_loop_context_data(self):
fields = self.node.properties.get('config', []).get('fields', []) or []
return {f.get('value'): self.context.get(f.get('value')) for f in fields if
self.context.get(f.get('value')) is not None}

def get_details(self, index: int, **kwargs):

return {
'name': self.node.properties.get('stepName'),
"index": index,
Expand All @@ -276,6 +285,7 @@ def get_details(self, index: int, **kwargs):
"current_item": self.context.get("item"),
'loop_type': self.node_params_serializer.data.get('loop_type'),
'status': self.status,
'loop_context_data': self.get_loop_context_data(),
'loop_node_data': self.context.get("loop_node_data"),
'loop_answer_data': self.context.get("loop_answer_data"),
'err_message': self.err_message
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code appears to be part of an artificial intelligence (AI) system designed to handle workflows with loop nodes and manage states. Here are some comments and suggestions for improving the code:

  1. Comments: Add more detailed comments explaining what each method does, especially the save_context and get_details methods.

  2. Variable Naming: Use descriptive variable names instead of abbreviations like _, which can make the code harder to read.

  3. Loop Context Data Logic: The logic for generating loop_context_data could potentially lead to unnecessary overhead if certain fields always have valid values. Make sure this logic is optimal based on your needs.

  4. Error Handling: Enhance error handling in critical sections such as saving context and fetching data.

  5. Concurrency Considerations: If the workflow management involves concurrency, consider adding thread-safe operations to avoid data corruption.

Here's a revised version of the code with these considerations in mind:

class BaseLoopNode(ILoopNode):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Initialize variables here

    def save_context(self, details, workflow_manage):
        """
        Save contextual information from the provided details.

        :param details: Dictionary containing result, additional context, etc.
        :param workflow_manage: Instance responsible for managing the workflow state.
        """
        self.context['result'] = details.get('result')
        for key, value in details['context'].items():
            # Avoid overwriting existing keys unless necessary
            if key not in self.context:
                self.context[key] = value
        
        # Ensure answer text is stringified
        self.answer_text = str(details.get('result'))

    def get_answer_list(self) -> List[Answer] | None:
        """
        Get the list of answers related to the current node.

        Returns:
            A list of Answer objects or None if no answers are available.
        """
        return [
            Answer(..., name=self.node.properties.get('stepName'), index=index, ...)
            for index in range(len(self.context["loop_answers"]))
        ]

def workflow_manage_new_instance(
    loop_data: dict,
    global_data: dict,
    start_node_id=None,
    _write_context=get_write_context,
    _is_interrupt=_is_interrupt_exec
):
    """
    Manage the creation of a new instance within a workflow.

    Parameters:
        loop_data: Configuration data for loops.
        global_data: Global workflow data.
        start_node_id: ID of the starting node.
        _write_context: Function to write contextual information.
        _is_interrupt: Function to determine interruption status.

    Returns:
        An instance of a WorkflowManagement class managing the created instance.
    """
    # Implementation goes here

def get_loop_context_data(self) -> Dict[str, Any]:
    """Generate specific context data relevant to this loop."""
    fields = self.node.properties.get('config', {}).get('fields', [])
    
    # Filter fields that exist in the context
    return {
        field.get('value'): self.context.get(field.get('value'))
        for field in filter(lambda x: x.get('value') is not None, fields)
    }

def get_details(self, index: int, **kwargs) -> dict:
    """
    Retrieve detailed information about the current step.

    Parameters:
        index: Index identifying the specific detail required.
        **kwargs: Additional keyword arguments for customization.

    Returns:
        A dictionary containing various details about the current step.
    """
    return {
        "name": self.node.properties.get('stepName'),
        "index": index,
        "error_message": kwargs.pop("err_message", ""),
        "current_item": self.context.get("item"),
        'loop_type': self.node_params_serializer.data.get('loop_type'),
        'status': self.status,
        'loop_context_data': self.get_loop_context_data(),
        'loop_node_data': self.context.get("loop_node_data"),
        'loop_answer_data': self.context.get("loop_answer_data")
    }

These changes focus on clarity, readability, and maintainability while ensuring that the core functionality remains intact.

Expand Down
3 changes: 3 additions & 0 deletions apps/application/flow/workflow_manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ def get_node_params(n):
{**self.start_node.node_params, 'form_data': start_node_data}, self.start_node.workflow_params)
if self.start_node.type == 'loop-node':
loop_node_data = node_details.get('loop_node_data', {})
for k, v in node_details.get('loop_context_data').items():
if v is not None:
self.start_node.context[k] = v
self.start_node.context['loop_node_data'] = loop_node_data
self.start_node.context['current_index'] = node_details.get('current_index')
self.start_node.context['current_item'] = node_details.get('current_item')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code appears to be part of a function aimed at retrieving parameters for a node, including handling loop nodes. There are a few optimizations and improvements that can be made:

  1. Use get method with default values: To make the code more robust against missing keys in node_details, use the get method with appropriate default values.

  2. Avoid multiple assignments within loop contexts: If loop_context_data contains many entries, avoid making multiple assignments within a loop. Instead, initialize a dictionary outside the loop and populate it during iteration.

  3. Consider using data classes or dictionaries for consistency: Ensure that the data structure being used (dictionary vs. data class) remains consistent throughout the codebase for better manageability and type safety.

  4. Error Handling: Add error handling around network requests (if applicable) to manage exceptions gracefully.

Here's an optimized version of the code incorporating some of these suggestions:

def get_node_params(n):
    start_node_data = node_details.get('start_node_data', {})

    if n.start_node.type == 'loop-node':
        loop_node_data = node_details.get('loop_node_data', {})
        
        # Initialize context dictionary outside the loop for efficiency
        updated_context = {}

        for k, v in node_details.get('loop_context_data', {}).items():
            if v is not None:
                updated_context[k] = v

        self.start_node.context.update(updated_context)
        self.start_node.context['loop_node_data'] = loop_node_data
        self.start_node.context['current_index'] = node_details.get('current_index', 0)
        self.start_node.context['current_item'] = node_details.get('current_item')

    return params_dict  # Replace 'params_dict' with actual parameter dict logic

This refactored version uses a dictionary updated_context to accumulate loop context values before updating the context field of self.start_node. This reduces redundancy and improves readability.

Expand Down
Loading