vectorvein 0.2.64__py3-none-any.whl → 0.2.66__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ from typing import List, Union, Dict, Any, Optional
3
3
 
4
4
  from .node import Node
5
5
  from .edge import Edge
6
+ from .port import InputPort, OutputPort
6
7
  from ..utils.layout import layout
7
8
  from ..utils.check import (
8
9
  WorkflowCheckResult,
@@ -168,3 +169,171 @@ class Workflow:
168
169
  """
169
170
  layout(self.nodes, self.edges, options)
170
171
  return self
172
+
173
+ @classmethod
174
+ def from_json(cls, json_str: str) -> "Workflow":
175
+ """从 JSON 字符串创建工作流对象。
176
+
177
+ Args:
178
+ json_str: JSON 字符串
179
+
180
+ Returns:
181
+ Workflow: 工作流对象
182
+ """
183
+ workflow = cls()
184
+ data = json.loads(json_str)
185
+
186
+ # 创建节点
187
+ for node_data in data.get("nodes", []):
188
+ node_type = node_data["type"]
189
+ category = node_data["category"]
190
+ task_name = node_data["data"]["task_name"]
191
+
192
+ # 尝试动态导入节点类
193
+ NodeClass = None
194
+ try:
195
+ # 如果task_name包含分类信息
196
+ if "." in task_name:
197
+ category, _ = task_name.split(".")
198
+ module_path = f"vectorvein.workflow.nodes.{category}"
199
+ module = __import__(module_path, fromlist=[node_type])
200
+ if hasattr(module, node_type):
201
+ NodeClass = getattr(module, node_type)
202
+ except (ImportError, AttributeError):
203
+ pass
204
+
205
+ if not NodeClass:
206
+ raise ValueError(f"Node class not found: {node_type}")
207
+ # 创建节点实例以获取默认值
208
+ node_instance = NodeClass()
209
+
210
+ # 使用节点实例的基本属性
211
+ node = Node(
212
+ node_type=node_type,
213
+ category=category,
214
+ task_name=task_name,
215
+ description=node_data["data"].get(
216
+ "description", node_instance.description if hasattr(node_instance, "description") else ""
217
+ ),
218
+ node_id=node_data["id"],
219
+ position=node_data.get("position", {"x": 0, "y": 0}),
220
+ seleted_workflow_title=node_data["data"].get("seleted_workflow_title", ""),
221
+ is_template=node_data["data"].get("is_template", False),
222
+ initialized=node_data.get("initialized", False),
223
+ can_add_input_ports=node_data["data"].get("has_inputs", False),
224
+ can_add_output_ports=node_data["data"].get("has_outputs", False),
225
+ )
226
+
227
+ # 处理端口
228
+ for port_name, port_data in node_data["data"].get("template", {}).items():
229
+ # 如果端口已存在于节点实例中,直接修改其属性
230
+ if port_name in node_instance.ports:
231
+ # 直接修改原始端口的属性,而不是创建新端口
232
+ port = node_instance.ports[port_name]
233
+
234
+ # 更新端口的属性
235
+ if "field_type" in port_data:
236
+ port.port_type = port_data["field_type"]
237
+ if "required" in port_data:
238
+ port.required = port_data["required"]
239
+ if "show" in port_data:
240
+ port.show = port_data["show"]
241
+ if "value" in port_data:
242
+ port.value = port_data["value"]
243
+ if "options" in port_data:
244
+ port.options = port_data["options"]
245
+ if "type" in port_data:
246
+ port.field_type = port_data["type"]
247
+ if "max_length" in port_data:
248
+ port.max_length = port_data["max_length"]
249
+ if "support_file_types" in port_data and port_data["support_file_types"]:
250
+ port.support_file_types = port_data["support_file_types"].split(", ")
251
+ if "multiple" in port_data:
252
+ port.multiple = port_data["multiple"]
253
+ if "group" in port_data:
254
+ port.group = port_data["group"]
255
+ if "group_collpased" in port_data:
256
+ port.group_collpased = port_data["group_collpased"]
257
+ if "has_tooltip" in port_data:
258
+ port.has_tooltip = port_data["has_tooltip"]
259
+ if "max" in port_data:
260
+ port.max = port_data["max"]
261
+ if "min" in port_data:
262
+ port.min = port_data["min"]
263
+ if "list" in port_data:
264
+ port.list = port_data["list"]
265
+ else:
266
+ # 对于新添加的端口,检查是否允许添加
267
+ port_type = port_data.get("field_type", "text")
268
+ is_output = port_data.get("is_output", False)
269
+
270
+ # 检查节点是否允许添加该类型的端口
271
+ if (is_output and not node.can_add_output_ports) or (
272
+ not is_output and not node.can_add_input_ports
273
+ ):
274
+ # 如果不允许添加,跳过该端口
275
+ continue
276
+
277
+ # 创建并添加新端口
278
+ if is_output:
279
+ port = OutputPort(
280
+ name=port_name,
281
+ port_type=port_type,
282
+ required=port_data.get("required", False),
283
+ show=port_data.get("show", False),
284
+ value=port_data.get("value"),
285
+ options=port_data.get("options"),
286
+ field_type=port_data.get("type"),
287
+ max_length=port_data.get("max_length"),
288
+ support_file_types=port_data.get("support_file_types", "").split(", ")
289
+ if port_data.get("support_file_types")
290
+ else None,
291
+ multiple=port_data.get("multiple"),
292
+ group=port_data.get("group"),
293
+ group_collpased=port_data.get("group_collpased", False),
294
+ has_tooltip=port_data.get("has_tooltip", False),
295
+ max=port_data.get("max"),
296
+ min=port_data.get("min"),
297
+ list=port_data.get("list", False),
298
+ )
299
+ else:
300
+ port = InputPort(
301
+ name=port_name,
302
+ port_type=port_type,
303
+ required=port_data.get("required", True),
304
+ show=port_data.get("show", False),
305
+ value=port_data.get("value"),
306
+ options=port_data.get("options"),
307
+ field_type=port_data.get("type"),
308
+ max_length=port_data.get("max_length"),
309
+ support_file_types=port_data.get("support_file_types", "").split(", ")
310
+ if port_data.get("support_file_types")
311
+ else None,
312
+ multiple=port_data.get("multiple"),
313
+ group=port_data.get("group"),
314
+ group_collpased=port_data.get("group_collpased", False),
315
+ has_tooltip=port_data.get("has_tooltip", False),
316
+ max=port_data.get("max"),
317
+ min=port_data.get("min"),
318
+ list=port_data.get("list", False),
319
+ )
320
+
321
+ # 添加新端口到节点
322
+ node.ports[port_name] = port
323
+
324
+ workflow.add_node(node)
325
+
326
+ # 创建边
327
+ for edge_data in data.get("edges", []):
328
+ edge = Edge(
329
+ id=edge_data["id"],
330
+ source=edge_data["source"],
331
+ source_handle=edge_data["sourceHandle"],
332
+ target=edge_data["target"],
333
+ target_handle=edge_data["targetHandle"],
334
+ animated=edge_data.get("animated", True),
335
+ type=edge_data.get("type", "default"),
336
+ )
337
+ workflow.add_edge(edge)
338
+
339
+ return workflow
@@ -86,6 +86,16 @@ def generate_python_code(
86
86
  node_imports = set()
87
87
  node_instances = {}
88
88
 
89
+ # 收集所有连接的端口
90
+ connected_ports = set()
91
+ for edge in workflow_data["edges"]:
92
+ source_id = edge["source"]
93
+ target_id = edge["target"]
94
+ source_handle = edge["sourceHandle"]
95
+ target_handle = edge["targetHandle"]
96
+ connected_ports.add((source_id, source_handle))
97
+ connected_ports.add((target_id, target_handle))
98
+
89
99
  # 解析节点并生成导入语句
90
100
  for node in workflow_data["nodes"]:
91
101
  node_type = node["type"]
@@ -125,7 +135,13 @@ def generate_python_code(
125
135
  port_value = port["value"]
126
136
  default_value = node_instance.ports[port_name].value if port_name in node_instance.ports else None
127
137
 
128
- if port_value and port_value != default_value:
138
+ # 判断端口是否有值且值与默认不同,并且端口满足以下条件之一:有连接、是输入端口、在UI上显示
139
+ port_is_connected = (node["id"], port["name"]) in connected_ports
140
+ if (
141
+ port_value
142
+ and port_value != default_value
143
+ and (port_is_connected or not port.get("is_output", False) or port.get("show", False))
144
+ ):
129
145
  values.append(port)
130
146
 
131
147
  node_instances[node["id"]] = {
@@ -156,6 +172,8 @@ def generate_python_code(
156
172
  code.append("")
157
173
  for node_info in node_instances.values():
158
174
  for port in node_info["add_ports"]:
175
+ if "name" not in port:
176
+ continue
159
177
  params = [
160
178
  f"name={to_python_str(port['name'])}",
161
179
  f"port_type={to_python_str(port['field_type'])}",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vectorvein
3
- Version: 0.2.64
3
+ Version: 0.2.66
4
4
  Summary: VectorVein Python SDK
5
5
  Author-Email: Anderson <andersonby@163.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
- vectorvein-0.2.64.dist-info/METADATA,sha256=Rd5tC_nxsZ9vTIatBOc10n_0OFxSwoK4gf8H_Jq39Pk,4570
2
- vectorvein-0.2.64.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- vectorvein-0.2.64.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1
+ vectorvein-0.2.66.dist-info/METADATA,sha256=F0vYXH6hGEh9Og1VPt3DWzsMEEwRESIgks7WjQj--NU,4570
2
+ vectorvein-0.2.66.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ vectorvein-0.2.66.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
4
  vectorvein/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  vectorvein/api/__init__.py,sha256=lfY-XA46fgD2iIZTU0VYP8i07AwA03Egj4Qua0vUKrQ,738
6
6
  vectorvein/api/client.py,sha256=xF-leKDQzVyyy9FnIRaz0k4eElYW1XbbzeRLcpnyk90,33047
@@ -44,7 +44,7 @@ vectorvein/utilities/retry.py,sha256=6KFS9R2HdhqM3_9jkjD4F36ZSpEx2YNFGOVlpOsUetM
44
44
  vectorvein/workflow/graph/edge.py,sha256=1ckyyjCue_PLm7P1ItUfKOy6AKkemOpZ9m1WJ8UXIHQ,1072
45
45
  vectorvein/workflow/graph/node.py,sha256=WtO4MkeMQr59zNl9N2ZoYiCZcVKxebSp1rKMPONmfqk,5628
46
46
  vectorvein/workflow/graph/port.py,sha256=HcinzQqNP7ysTvBmi3c4iaWne8nV6m-BpFFX0jTrMIE,7122
47
- vectorvein/workflow/graph/workflow.py,sha256=f5KAQUXTKii7UFYmSZeZZQ7JCKKPmJlUg0iFAfBEJQE,6366
47
+ vectorvein/workflow/graph/workflow.py,sha256=TfBvuspF1uHxmZl4VThgsXA07xiPvMT_mzd1oUvZ9Ww,14600
48
48
  vectorvein/workflow/nodes/__init__.py,sha256=dWrWtL3q0Vsn-MLgJ7gNgLCrwZ5BrqjrN2QFPNeBMuc,3240
49
49
  vectorvein/workflow/nodes/audio_generation.py,sha256=ZRFZ_ycMTSJ2LKmekctagQdJYTl-3q4TNOIKETpS9AM,5870
50
50
  vectorvein/workflow/nodes/control_flows.py,sha256=fDySWek8Isbfznwn0thmbTwTP4c99w68Up9dlASAtIo,6805
@@ -62,6 +62,6 @@ vectorvein/workflow/nodes/vector_db.py,sha256=p9AT_E8ASbcYHZqHYTCIGvqkIqzxaFM4Ux
62
62
  vectorvein/workflow/nodes/video_generation.py,sha256=qmdg-t_idpxq1veukd-jv_ChICMOoInKxprV9Z4Vi2w,4118
63
63
  vectorvein/workflow/nodes/web_crawlers.py,sha256=FB0bTimkk___p3Z5UwQx2YarJyQCc45jjnbXbgGA_qw,5640
64
64
  vectorvein/workflow/utils/check.py,sha256=Oj_S5WQf4_Fr_ro3ipjZt9unKFSFcuwZrrSmrS9kVLE,10193
65
- vectorvein/workflow/utils/json_to_code.py,sha256=zCobrmWN33WP6t7i5Yx-lAJMM_PbhJ4H1ckceGB6FqI,6292
65
+ vectorvein/workflow/utils/json_to_code.py,sha256=ozdENkT1fYO67XdZX3Una5_jhGEUJdwD0DfZh0x4q3w,7120
66
66
  vectorvein/workflow/utils/layout.py,sha256=j0bRD3uaXu40xCS6U6BGahBI8FrHa5MiF55GbTrZ1LM,4565
67
- vectorvein-0.2.64.dist-info/RECORD,,
67
+ vectorvein-0.2.66.dist-info/RECORD,,