Update process_flow_generator.py
Browse files- process_flow_generator.py +46 -53
process_flow_generator.py
CHANGED
@@ -25,35 +25,39 @@ def generate_process_flow_diagram(json_input: str, base_color: str) -> str:
|
|
25 |
"id": "step1",
|
26 |
"label": "Gather Requirements",
|
27 |
"type": "process",
|
28 |
-
"relationship": "Next"
|
29 |
-
"subnodes": [
|
30 |
-
{"id": "step1_1", "label": "Define Scope", "type": "process", "relationship": "Then"}
|
31 |
-
]
|
32 |
},
|
33 |
{
|
34 |
"id": "decision1",
|
35 |
"label": "Is Data Available?",
|
36 |
"type": "decision",
|
37 |
-
"relationship": "Check"
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
},
|
43 |
{
|
44 |
"id": "end_node",
|
45 |
"label": "End Process",
|
46 |
-
"type": "end"
|
47 |
-
"relationship": "Concludes"
|
48 |
}
|
49 |
],
|
50 |
"connections": [
|
51 |
-
{"from": "start_node", "to": "step1"},
|
52 |
-
{"from": "step1", "to": "decision1"},
|
53 |
{"from": "decision1", "to": "path_yes", "label": "Yes"},
|
54 |
{"from": "decision1", "to": "path_no", "label": "No"},
|
55 |
-
{"from": "path_yes", "to": "end_node"},
|
56 |
-
{"from": "path_no", "to": "end_node"}
|
57 |
]
|
58 |
}
|
59 |
"""
|
@@ -65,13 +69,13 @@ def generate_process_flow_diagram(json_input: str, base_color: str) -> str:
|
|
65 |
|
66 |
# Determine specific node shapes for flowchart types
|
67 |
node_shapes = {
|
68 |
-
"process": "box",
|
69 |
-
"decision": "diamond",
|
70 |
-
"start": "
|
71 |
-
"end": "
|
72 |
-
"io": "parallelogram",
|
73 |
-
"document": "note",
|
74 |
-
"default": "box"
|
75 |
}
|
76 |
|
77 |
dot = graphviz.Digraph(
|
@@ -81,45 +85,41 @@ def generate_process_flow_diagram(json_input: str, base_color: str) -> str:
|
|
81 |
'rankdir': 'TB', # Top-to-Bottom flow is common for flowcharts
|
82 |
'splines': 'ortho', # Straight lines with 90-degree bends
|
83 |
'bgcolor': 'white', # White background
|
84 |
-
'pad': '0.5'
|
85 |
-
|
86 |
-
|
|
|
87 |
)
|
88 |
|
|
|
|
|
|
|
|
|
89 |
# Add all nodes based on JSON structure
|
90 |
-
|
|
|
91 |
if 'start_node' in data:
|
92 |
-
|
93 |
|
94 |
for node_data in data.get('nodes', []):
|
95 |
-
|
96 |
|
97 |
-
|
98 |
-
for node_id, node_info in all_nodes.items():
|
99 |
node_type = node_info.get("type", "default")
|
100 |
shape = node_shapes.get(node_type, "box") # Default to box if type is unknown
|
101 |
|
102 |
-
#
|
103 |
-
#
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
# Simple color lightening for sub-levels if 'subnodes' are used in a nested process
|
108 |
-
# This logic mimics graph_generator_utils but is adapted for the specific flow structure
|
109 |
-
# For a pure flowchart, often nodes are all the same color.
|
110 |
-
# If you want gradient for subprocesses, the current_depth logic needs to be more robust for different node types.
|
111 |
-
|
112 |
-
# Let's use base_color directly for all main nodes and only apply gradient for 'subnodes'
|
113 |
-
# For now, we'll pass current_depth=0 to add_nodes_and_edges when called recursively
|
114 |
-
# to ensure the main flow nodes are consistent.
|
115 |
|
116 |
dot.node(
|
117 |
node_id,
|
118 |
node_info['label'],
|
119 |
shape=shape,
|
120 |
-
style='filled,rounded',
|
121 |
-
fillcolor=
|
122 |
-
fontcolor=
|
123 |
fontsize='14'
|
124 |
)
|
125 |
|
@@ -134,13 +134,6 @@ def generate_process_flow_diagram(json_input: str, base_color: str) -> str:
|
|
134 |
fontsize='10'
|
135 |
)
|
136 |
|
137 |
-
# If there's a start_node, ensure it's visually marked
|
138 |
-
if 'start_node' in data:
|
139 |
-
dot.node(data['start_node'], data['start_node'], shape=node_shapes['start'], style='filled,rounded', fillcolor='#2196F3', fontcolor='white', fontsize='14')
|
140 |
-
if 'end_node' in data and data['end_node'] in all_nodes:
|
141 |
-
dot.node(data['end_node'], all_nodes[data['end_node']]['label'], shape=node_shapes['end'], style='filled,rounded', fillcolor='#F44336', fontcolor='white', fontsize='14')
|
142 |
-
|
143 |
-
|
144 |
# Save to temporary file
|
145 |
with NamedTemporaryFile(delete=False, suffix='.png') as tmp:
|
146 |
dot.render(tmp.name, format='png', cleanup=True)
|
|
|
25 |
"id": "step1",
|
26 |
"label": "Gather Requirements",
|
27 |
"type": "process",
|
28 |
+
"relationship": "Next"
|
|
|
|
|
|
|
29 |
},
|
30 |
{
|
31 |
"id": "decision1",
|
32 |
"label": "Is Data Available?",
|
33 |
"type": "decision",
|
34 |
+
"relationship": "Check"
|
35 |
+
},
|
36 |
+
{
|
37 |
+
"id": "path_yes",
|
38 |
+
"label": "Process Data",
|
39 |
+
"type": "process",
|
40 |
+
"relationship": "Yes"
|
41 |
+
},
|
42 |
+
{
|
43 |
+
"id": "path_no",
|
44 |
+
"label": "Collect More Data",
|
45 |
+
"type": "process",
|
46 |
+
"relationship": "No"
|
47 |
},
|
48 |
{
|
49 |
"id": "end_node",
|
50 |
"label": "End Process",
|
51 |
+
"type": "end"
|
|
|
52 |
}
|
53 |
],
|
54 |
"connections": [
|
55 |
+
{"from": "start_node", "to": "step1", "label": "Start"},
|
56 |
+
{"from": "step1", "to": "decision1", "label": "Continue"},
|
57 |
{"from": "decision1", "to": "path_yes", "label": "Yes"},
|
58 |
{"from": "decision1", "to": "path_no", "label": "No"},
|
59 |
+
{"from": "path_yes", "to": "end_node", "label": "Done"},
|
60 |
+
{"from": "path_no", "to": "end_node", "label": "Done"}
|
61 |
]
|
62 |
}
|
63 |
"""
|
|
|
69 |
|
70 |
# Determine specific node shapes for flowchart types
|
71 |
node_shapes = {
|
72 |
+
"process": "box", # Rectangle for processes
|
73 |
+
"decision": "diamond", # Diamond for decisions
|
74 |
+
"start": "oval", # Oval for start
|
75 |
+
"end": "oval", # Oval for end
|
76 |
+
"io": "parallelogram", # Input/Output
|
77 |
+
"document": "note", # Document symbol
|
78 |
+
"default": "box" # Fallback
|
79 |
}
|
80 |
|
81 |
dot = graphviz.Digraph(
|
|
|
85 |
'rankdir': 'TB', # Top-to-Bottom flow is common for flowcharts
|
86 |
'splines': 'ortho', # Straight lines with 90-degree bends
|
87 |
'bgcolor': 'white', # White background
|
88 |
+
'pad': '0.5', # Padding around the graph
|
89 |
+
'nodesep': '0.6', # Spacing between nodes on same rank
|
90 |
+
'ranksep': '0.8' # Spacing between ranks
|
91 |
+
}
|
92 |
)
|
93 |
|
94 |
+
# Ensure base_color is valid, fallback if not
|
95 |
+
if not isinstance(base_color, str) or not base_color.startswith('#') or len(base_color) != 7:
|
96 |
+
base_color = '#19191a' # Fallback to default dark if invalid
|
97 |
+
|
98 |
# Add all nodes based on JSON structure
|
99 |
+
all_nodes_data = {}
|
100 |
+
# Special handling for start_node if defined separately
|
101 |
if 'start_node' in data:
|
102 |
+
all_nodes_data[data['start_node']] = {"label": data['start_node'], "type": "start"}
|
103 |
|
104 |
for node_data in data.get('nodes', []):
|
105 |
+
all_nodes_data[node_data['id']] = node_data
|
106 |
|
107 |
+
for node_id, node_info in all_nodes_data.items():
|
|
|
108 |
node_type = node_info.get("type", "default")
|
109 |
shape = node_shapes.get(node_type, "box") # Default to box if type is unknown
|
110 |
|
111 |
+
# Use base_color for all nodes for consistent flowchart look
|
112 |
+
# You can adapt add_nodes_and_edges if you want color gradient per depth for flowcharts too
|
113 |
+
fill_color_for_node = base_color
|
114 |
+
font_color_for_node = 'white' if base_color == '#19191a' else 'black' # Keep text readable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
dot.node(
|
117 |
node_id,
|
118 |
node_info['label'],
|
119 |
shape=shape,
|
120 |
+
style='filled,rounded', # Keep rounded corners
|
121 |
+
fillcolor=fill_color_for_node,
|
122 |
+
fontcolor=font_color_for_node,
|
123 |
fontsize='14'
|
124 |
)
|
125 |
|
|
|
134 |
fontsize='10'
|
135 |
)
|
136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
# Save to temporary file
|
138 |
with NamedTemporaryFile(delete=False, suffix='.png') as tmp:
|
139 |
dot.render(tmp.name, format='png', cleanup=True)
|