vectorvein 0.2.63__py3-none-any.whl → 0.2.65__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
@@ -150,11 +150,14 @@ def generate_python_code(
150
150
 
151
151
  # 添加节点到工作流
152
152
  node_list = [f" {info['var_name']}," for info in node_instances.values()]
153
- code.append(f"workflow.add_nodes([\n{'\n'.join(node_list)}\n])")
153
+ node_list_str = "\n".join(node_list)
154
+ code.append(f"workflow.add_nodes([\n{node_list_str}\n])")
154
155
 
155
156
  code.append("")
156
157
  for node_info in node_instances.values():
157
158
  for port in node_info["add_ports"]:
159
+ if "name" not in port:
160
+ continue
158
161
  params = [
159
162
  f"name={to_python_str(port['name'])}",
160
163
  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.63
3
+ Version: 0.2.65
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.63.dist-info/METADATA,sha256=bp_MfR1VH9x50C2uHRYOeHF77enWRykynnuWFX8eJe4,4570
2
- vectorvein-0.2.63.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- vectorvein-0.2.63.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1
+ vectorvein-0.2.65.dist-info/METADATA,sha256=uzmiNET17QtrxVT2HdpBs68JBFwNXkDdfIQ_0HG8-b4,4570
2
+ vectorvein-0.2.65.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ vectorvein-0.2.65.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=U9EF62D270Ff1D8JKH3Am_jwsiDkSLeC41MZz7rZ8hg,6257
65
+ vectorvein/workflow/utils/json_to_code.py,sha256=eeOxtlAUWeEgUyFVawDjee3nIhonnROUUanyf1-l9Ro,6354
66
66
  vectorvein/workflow/utils/layout.py,sha256=j0bRD3uaXu40xCS6U6BGahBI8FrHa5MiF55GbTrZ1LM,4565
67
- vectorvein-0.2.63.dist-info/RECORD,,
67
+ vectorvein-0.2.65.dist-info/RECORD,,