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
22 changes: 17 additions & 5 deletions apps/application/flow/workflow_manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import json
import threading
import traceback
import uuid
from concurrent.futures import ThreadPoolExecutor
from functools import reduce
from typing import List, Dict
Expand Down Expand Up @@ -575,7 +576,7 @@ def get_runtime_details(self):
details['node_id'] = node.id
details['up_node_id_list'] = node.up_node_id_list
details['runtime_node_id'] = node.runtime_node_id
details_result[node.runtime_node_id] = details
details_result[str(uuid.uuid1())] = details
return details_result

def get_answer_text_list(self):
Expand Down Expand Up @@ -664,9 +665,18 @@ def get_next_node_list(self, current_node, current_node_result):
for edge in self.flow.edges:
if (edge.sourceNodeId == current_node.id and
f"{edge.sourceNodeId}_{current_node_result.node_variable.get('branch_id')}_right" == edge.sourceAnchorId):
if self.dependent_node_been_executed(edge.targetNodeId):
next_node = [node for node in self.flow.nodes if node.id == edge.targetNodeId]
if len(next_node) == 0:
continue
if next_node[0].properties.get('condition', "AND") == 'AND':
if self.dependent_node_been_executed(edge.targetNodeId):
node_list.append(
self.get_node_cls_by_id(edge.targetNodeId,
[*current_node.up_node_id_list, current_node.node.id]))
else:
node_list.append(
self.get_node_cls_by_id(edge.targetNodeId, self.get_up_node_id_list(edge.targetNodeId)))
self.get_node_cls_by_id(edge.targetNodeId,
[*current_node.up_node_id_list, current_node.node.id]))
else:
for edge in self.flow.edges:
if edge.sourceNodeId == current_node.id:
Expand All @@ -676,10 +686,12 @@ def get_next_node_list(self, current_node, current_node_result):
if next_node[0].properties.get('condition', "AND") == 'AND':
if self.dependent_node_been_executed(edge.targetNodeId):
node_list.append(
self.get_node_cls_by_id(edge.targetNodeId, self.get_up_node_id_list(edge.targetNodeId)))
self.get_node_cls_by_id(edge.targetNodeId,
[*current_node.up_node_id_list, current_node.node.id]))
else:
node_list.append(
self.get_node_cls_by_id(edge.targetNodeId, [current_node.node.id]))
self.get_node_cls_by_id(edge.targetNodeId,
[*current_node.up_node_id_list, current_node.node.id]))
return node_list

def get_reference_field(self, node_id: str, fields: List[str]):
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 contains several irregularities:

1. **Duplicated Code Blocks**: In `get_next_node_list`, there's nearly identical logic in both branches but different variable names (`current_node_result.node_variable` vs `next_node_list`). This redundancy can be improved by refactoring this block to reduce duplication.

   ```diff
   -                    node_list.append(
-                                    self.get_node_cls_by_id(edge.targetNodeId, [*current_node.up_node_id_list, current_node.node.id]))
+                      # Common logic for handling AND-conditioned nodes
                     if (
                         next_node[0].properties.get('condition', "AND") == 'AND' and
                         not self.dependent_node_been_executed(edge.targetNodeId)
                     ):
                         node_list.append(
                             self.get_node_cls_by_id(edge.targetNodeId,
                                                     [*current_node.up_node_id_list, current_node.node.id])
                         )
     ```

2. **Unnecessary Variable Assignments**:
   - Inside the first branch of `get_next_node_list`, where `self.dependent_node_been_executed(edge.targetNodeId)` is used to decide whether to append to `node_list`.
   - Similarly, inside the second branch.

3. **Improper UUID Usage**: The line `details_result[str(uuid.uuid1())] = details` should use a more descriptive key name than a generated UUID, especially considering it could lead to duplicate keys if a single node ID is encountered multiple times.

4. **Error Handling**: No error-handling mechanisms are present when calling methods like `dependent_node_been_executed`. For better robustness, these calls might need wrap with try-except blocks or add checks before execution.

5. **Variable Naming Consistency**: Some variable names seem inconsistent (e.g., `upNodeIDList` vs. `up_node_id_list`) which can make the code harder to read, though most inconsistencies were found within small scopes.

6. **Potential Race Conditions**: Since threading is used via `ThreadPoolExecutor`, ensure that any shared data structures between threads are properly synchronized or guarded against concurrent access, as Python has no built-in mutexes without using a third-party library such as `threading.Lock`.

7. **Complexity and Readability**: Although concise for typical purposes, some functions could benefit from additional comments explaining complex logic decisions or flow control paths, although the existing explanations might have already been clear.

Suggested changes:

```python
def get_next_node_list(self, current_node, current_node_result):
    result = []
    
    for edge in self.flow.edges:
        if (edge.sourceNodeId == current_node.id and
                edge.sourceAnchorId.startswith(f"{edge.sourceNodeId}_{current_node_result.node_variable.get('branch_id')}_right")):
            
            target_node_ids = [
                node.id 
                for node in self.flow.nodes 
                if node.id == edge.targetNodeId
            ]
            
            condition_value = next_node[0].properties.get('condition') or "AND"
            should_execute = True
            
            if condition_value == "AND":
                dependency_state = self.dependent_node_been_executed(target_node_ids)
                
                if dependency_state != NodeDependencyState.ALL_BEEN_EXECUTED:
                    should_execute = False
            elif condition_value != "OR":
                raise ValueError("Unsupported condition value")

            if should_execute:
                result.append(self.get_node_class_for_edge(edge))
        
        elif edge.sourceNodeId == current_node.id:
            next_node_list = [
                node for node in self.flow.nodes 
                if node.id == edge.targetNodeId
            ]

            if not next_node_list:
                continue

            condition_value = next_node_list[0].properties.get('condition') or "AND"

            if condition_value == "AND":
                if not self.dependent_node_been_executed(next_node_list[0].id):
                    result.extend([self.get_node_class_for_edge(edge)])
                    
                elif condition_value == "OR":
                    result.extend(self.extract_target_nodes(next_node_list))

    return result

And also consider adding proper exception handling around dependent_node_been_executed function calls.

Remember it's important to thoroughly test after making such refactorings to catch bugs introduced during restructure.

Expand Down
16 changes: 7 additions & 9 deletions ui/src/api/type/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,11 @@ export class ChatRecordManage {

this.chat.answer_text = this.chat.answer_text + chunk_answer
}
get_current_up_node() {
for (let i = this.node_list.length - 2; i >= 0; i--) {
const n = this.node_list[i]
if (n.content.length > 0) {
return n
}
get_current_up_node(run_node: any) {
const index = this.node_list.findIndex((item) => item == run_node)
if (index > 0) {
const n = this.node_list[index - 1]
return n
}
return undefined
}
Expand All @@ -145,14 +144,13 @@ export class ChatRecordManage {
const index = this.node_list.indexOf(run_node)
let current_up_node = undefined
if (index > 0) {
current_up_node = this.get_current_up_node()
current_up_node = this.get_current_up_node(run_node)
}
let answer_text_list_index = 0

if (
current_up_node == undefined ||
run_node.view_type == 'single_view' ||
(run_node.view_type == 'many_view' && current_up_node.view_type == 'single_view')
current_up_node.view_type == 'single_view'
) {
const none_index = this.findIndex(
this.chat.answer_text_list,
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 code has a few issues that need attention:

  1. Logical Error in get_current_up_node:
    The second argument in this.get_current_up_node(run_node) is unnecessary because you're already passing run_node as an input to the function inside.

  2. Inconsistency in Code Formatting:
    There are some inconsistencies in line numbers in different parts of the code, which can make it harder to track.

  3. Redundant Conditional Checks:
    Some conditional checks are redundant due to earlier conditions being satisfied.

Here's a cleaned-up version of the code with these issues addressed:

export class ChatRecordManage  {
    chat.answer_text = this.chat.answer_text + chunk_answer
}

get_current_up_node(run_node) {
    const index = this.node_list.findIndex(item => item === run_node);
    if (index > 0) {
        const n = this.node_list[index - 1];
        return n;
    }
    return undefined;
}

processNextNode(run_node) {
    const currentIndex = this.node_list.indexOf(run_node);
    if (currentIndex < this.node_list.length - 1) { // Check for boundary condition
        const nextNode = this.node_list[currentIndex + 1];
        if (
            current_node == undefined || 
            run_node.view_type === 'single_view' || 
            (run_node.view_type === 'many_view' && current_node.view_type === "signle_view")
        ) {
            const non_index = this.findIndex(this.chat.answer_text_list , ...); // Complete logic here based on context
        }
    }
}

Suggestions:

  • Remove the extra parameter from get_current_up_node.
  • Simplify and remove redundant checks for currentUpNode == undefined.
  • Ensure proper indentation throughout the file.

Expand Down
Loading