vectorvein 0.2.55__py3-none-any.whl → 0.2.57__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.
@@ -52,24 +52,28 @@ class AddData(Node):
52
52
  {"value": "table", "label": "table"},
53
53
  ],
54
54
  condition="return fieldsData.data_type.value == 'text'",
55
+ condition_python=lambda ports: ports["data_type"].value == "text",
55
56
  ),
56
57
  "chunk_length": InputPort(
57
58
  name="chunk_length",
58
59
  port_type=PortType.NUMBER,
59
60
  value=500,
60
61
  condition="return ['general', 'markdown'].includes(fieldsData.split_method.value)",
62
+ condition_python=lambda ports: ports["split_method"].value in ["general", "markdown"],
61
63
  ),
62
64
  "chunk_overlap": InputPort(
63
65
  name="chunk_overlap",
64
66
  port_type=PortType.NUMBER,
65
67
  value=30,
66
68
  condition="return ['general', 'markdown'].includes(fieldsData.split_method.value)",
69
+ condition_python=lambda ports: ports["split_method"].value in ["general", "markdown"],
67
70
  ),
68
71
  "delimiter": InputPort(
69
72
  name="delimiter",
70
73
  port_type=PortType.INPUT,
71
74
  value="\\n",
72
75
  condition="return fieldsData.split_method.value == 'delimiter'",
76
+ condition_python=lambda ports: ports["split_method"].value == "delimiter",
73
77
  ),
74
78
  "remove_url_and_email": InputPort(
75
79
  name="remove_url_and_email",
@@ -138,6 +138,7 @@ class YoutubeCrawler(Node):
138
138
  {"value": "detailed", "label": "detailed"},
139
139
  ],
140
140
  condition="return fieldsData.get_comments.value",
141
+ condition_python=lambda ports: ports["get_comments"].value,
141
142
  ),
142
143
  "output_type": InputPort(
143
144
  name="output_type",
@@ -5,6 +5,7 @@ from ..graph.port import InputPort
5
5
  if TYPE_CHECKING:
6
6
  from ..graph.workflow import Workflow
7
7
  from ..graph.node import Node
8
+ from ..graph.port import Port
8
9
 
9
10
 
10
11
  class UIWarning(TypedDict, total=False):
@@ -22,6 +23,8 @@ class WorkflowCheckResult(TypedDict):
22
23
  no_isolated_nodes: bool # 工作流是否不包含孤立节点
23
24
  useless_nodes: list["Node"] # 工作流中无用的节点
24
25
  ui_warnings: UIWarning # UI相关警告
26
+ required_ports: list[tuple["Node", "Port"]] # 未连接的必填端口
27
+ override_ports: list[tuple["Node", "Port"]] # 被覆盖的端口
25
28
 
26
29
 
27
30
  def check_dag(workflow: "Workflow"):
@@ -180,3 +183,79 @@ def check_useless_nodes(workflow: "Workflow") -> list["Node"]:
180
183
  useless_nodes.append(node)
181
184
 
182
185
  return useless_nodes
186
+
187
+
188
+ def check_required_ports(workflow: "Workflow") -> "list[tuple[Node, Port]]":
189
+ """检查工作流中是否存在未连接的空的必填端口。"""
190
+ required_but_not_connected = []
191
+
192
+ # 找出所有连接的目标端口
193
+ connected_ports = {(edge.target, edge.target_handle) for edge in workflow.edges}
194
+
195
+ # 遍历所有节点及其端口
196
+ for node in workflow.nodes:
197
+ ports = node.ports if hasattr(node, "ports") else {}
198
+ for port_name, port in ports.items():
199
+ # 检查条件是否适用
200
+ condition_applies = True
201
+ if hasattr(port, "condition_python") and port.condition_python is not None:
202
+ try:
203
+ # 检查是否为可调用函数
204
+ if callable(port.condition_python):
205
+ # 如果是函数,传入ports作为参数
206
+ condition_result = port.condition_python(ports)
207
+ else:
208
+ raise ValueError(
209
+ f"condition_python 必须是可调用函数,当前类型为 {type(port.condition_python)}"
210
+ )
211
+
212
+ if not condition_result:
213
+ condition_applies = False
214
+ except Exception:
215
+ # 如果条件评估出错,假设条件不适用
216
+ condition_applies = False
217
+
218
+ # 检查端口是否必填
219
+ is_required = getattr(port, "required", False)
220
+
221
+ # 检查值是否为空
222
+ value_is_empty = getattr(port, "value", "") == ""
223
+
224
+ # 检查是否没有连线连接到这个端口
225
+ not_connected = (node.id, port_name) not in connected_ports
226
+
227
+ # 如果满足所有条件,将其添加到结果列表
228
+ if condition_applies and is_required and value_is_empty and not_connected:
229
+ required_but_not_connected.append((node, port))
230
+
231
+ return required_but_not_connected
232
+
233
+
234
+ def check_override_ports(workflow: "Workflow") -> list[tuple["Node", "Port"]]:
235
+ """检查工作流中是否存在覆盖的端口。
236
+
237
+ 一个端口如果其 value 值不是布尔值,且不为空(空字符串、空列表、空字典),
238
+ 然后还被一个连线作为输出端口连接了,那么这个端口的 value 值会被覆盖。
239
+ """
240
+ override_ports = []
241
+
242
+ # 找出所有作为输出端口的连接
243
+ target_ports = {(edge.target, edge.target_handle) for edge in workflow.edges}
244
+
245
+ for node in workflow.nodes:
246
+ for port_name, port in node.ports.items():
247
+ # 检查端口是否被作为输出端口连接
248
+ if (node.id, port_name) in target_ports:
249
+ value = port.value
250
+
251
+ # 检查 value 是否为布尔值
252
+ if isinstance(value, bool):
253
+ continue
254
+
255
+ # 检查 value 是否为空
256
+ is_empty = value == "" or value == [] or value == {} or value is None
257
+
258
+ if not is_empty:
259
+ override_ports.append((node, port))
260
+
261
+ return override_ports
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vectorvein
3
- Version: 0.2.55
3
+ Version: 0.2.57
4
4
  Summary: VectorVein Python SDK
5
5
  Author-Email: Anderson <andersonby@163.com>
6
6
  License: MIT
@@ -1,13 +1,13 @@
1
- vectorvein-0.2.55.dist-info/METADATA,sha256=7dHFtxetkWiEk21XkKg4ob5uAjBppVwkf0KpA17tRGo,4570
2
- vectorvein-0.2.55.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- vectorvein-0.2.55.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1
+ vectorvein-0.2.57.dist-info/METADATA,sha256=VJeKL2r_44yXAPf6bThgchug8uSWNxcx3IR2zB6iwyM,4570
2
+ vectorvein-0.2.57.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ vectorvein-0.2.57.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
7
7
  vectorvein/api/exceptions.py,sha256=uS_PAdx0ksC0r3dgfSGWdbLMZm4qdLeWSSqCv1g3_Gc,772
8
8
  vectorvein/api/models.py,sha256=xtPWMsB0yIJI7i-gY4B6MtvXv0ZIXnoeKspmeInH6fU,1449
9
9
  vectorvein/chat_clients/__init__.py,sha256=UIytpIgwo8qkZpIyrHVxLYTyliUOTp4J7C4iHRjbtWE,23850
10
- vectorvein/chat_clients/anthropic_client.py,sha256=lvnE7IrtRehjiuXirhy09VH1NqiV5RFakfG8JAb9WNk,68362
10
+ vectorvein/chat_clients/anthropic_client.py,sha256=yrGb87h_hpxhK-O3Ir0L5yMHLimPgzaJqdW4AjzskHk,68924
11
11
  vectorvein/chat_clients/baichuan_client.py,sha256=CVMvpgjdrZGv0BWnTOBD-f2ufZ3wq3496wqukumsAr4,526
12
12
  vectorvein/chat_clients/base_client.py,sha256=p7s-G4Wh9MSpDKEfG8wuFAeWy5DGvj5Go31hqrpQPhM,38817
13
13
  vectorvein/chat_clients/deepseek_client.py,sha256=3qWu01NlJAP2N-Ff62d5-CZXZitlizE1fzb20LNetig,526
@@ -43,25 +43,25 @@ vectorvein/utilities/rate_limiter.py,sha256=dwolIUVw2wP83Odqpx0AAaE77de1GzxkYDGH
43
43
  vectorvein/utilities/retry.py,sha256=6KFS9R2HdhqM3_9jkjD4F36ZSpEx2YNFGOVlpOsUetM,2208
44
44
  vectorvein/workflow/graph/edge.py,sha256=1ckyyjCue_PLm7P1ItUfKOy6AKkemOpZ9m1WJ8UXIHQ,1072
45
45
  vectorvein/workflow/graph/node.py,sha256=ZzOhl7pltPBR5gyyL2ZtYeByPxjDPnM179emliqGFi8,5192
46
- vectorvein/workflow/graph/port.py,sha256=_QpHCBGAu657VhYAh0Wzjri3ZZ8-WYJp99J465mqmwo,6492
47
- vectorvein/workflow/graph/workflow.py,sha256=lDF4LafX5dmzjQQqR-mFhqQPdF_AKodiHpM3MygoqyE,6086
46
+ vectorvein/workflow/graph/port.py,sha256=HcinzQqNP7ysTvBmi3c4iaWne8nV6m-BpFFX0jTrMIE,7122
47
+ vectorvein/workflow/graph/workflow.py,sha256=f5KAQUXTKii7UFYmSZeZZQ7JCKKPmJlUg0iFAfBEJQE,6366
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
- vectorvein/workflow/nodes/control_flows.py,sha256=l8CjFQlsGV3fNGM6SVzS1Kz361K1xDv1fGT7acuDXuU,6613
51
- vectorvein/workflow/nodes/file_processing.py,sha256=h9FZM88ZAaLZq6obGCTs6mRXF6uYkwqca5JEiFxmd_k,4044
52
- vectorvein/workflow/nodes/image_generation.py,sha256=MJ628Luc5CwDWTu3uYM_nkIe6JgSV6Gqv0IiOrrsKm8,33699
53
- vectorvein/workflow/nodes/llms.py,sha256=_q65zdfugjNh1N83dytHG69TfkmpOPw2lwxKQUQnmrs,38589
54
- vectorvein/workflow/nodes/media_editing.py,sha256=hqOQCqxCPYdpnswlj4XM9fLRFJ0BTWUxW_oKH650hGs,29845
55
- vectorvein/workflow/nodes/media_processing.py,sha256=0NuJCkcRY68yO9ZJ7xmXA8RXXxPvptu_89nR83pxTEk,20066
56
- vectorvein/workflow/nodes/output.py,sha256=_UQxiddHtGv2rkjhUFE-KDgrjnh0AGJQJyq9-4Aji5A,12567
57
- vectorvein/workflow/nodes/relational_db.py,sha256=zfzUhV25TpZGhkIzO18PmAT5xhcsJC4AXKy0zyA05w8,5408
58
- vectorvein/workflow/nodes/text_processing.py,sha256=MRo_-oaC65hbzMxm7TYoeiS3rgvqh9y_Rny5RCfoATE,8342
59
- vectorvein/workflow/nodes/tools.py,sha256=n3gF7r5FqNz4Xg0nXYo5kl4ai_g4tWSRHqfnGrKJAls,13850
50
+ vectorvein/workflow/nodes/control_flows.py,sha256=fDySWek8Isbfznwn0thmbTwTP4c99w68Up9dlASAtIo,6805
51
+ vectorvein/workflow/nodes/file_processing.py,sha256=f4PlfgSAVFhwuqcEAvcLarNIkHUFP4FJucxnb3kekTU,4498
52
+ vectorvein/workflow/nodes/image_generation.py,sha256=a1ObkmvM8dwMxQvsnoYJwaURn0WwLXsqVkPybRnXT9A,35708
53
+ vectorvein/workflow/nodes/llms.py,sha256=ePnWAF4q-Uai5ZHgrYb7ZeoWzjIZ9B8XGAPPT5QEO10,40238
54
+ vectorvein/workflow/nodes/media_editing.py,sha256=ut4NN9_VUqnsqT2rlv0JrLhyxRLNUkvHb0c4QZDiKz8,34320
55
+ vectorvein/workflow/nodes/media_processing.py,sha256=_YuoJur2EeIeZfg8dSigDtqYcUpN6uVjGXJSVNqa6uI,22067
56
+ vectorvein/workflow/nodes/output.py,sha256=JHp-Y9EtuwD9qtZvVV2zHkH1OEK_6xlYh_DT1LrKuBs,13174
57
+ vectorvein/workflow/nodes/relational_db.py,sha256=Zg4G3xIQ94uoWE-Z4YER1bBhWgBQ6mYbJVQDeAN895I,5498
58
+ vectorvein/workflow/nodes/text_processing.py,sha256=BRmFSyLPADFplbUqUNjoJdmHzQvrPknJvBvvgtzaklk,8744
59
+ vectorvein/workflow/nodes/tools.py,sha256=ejIQO2hfuRr6m1jc9NMZEUK9ABEWPpX0PVO_UA5BtSc,13853
60
60
  vectorvein/workflow/nodes/triggers.py,sha256=BolH4X6S8HSuU2kwHmYKr-ozHbgKBmdZRcnXpK5EfGA,597
61
- vectorvein/workflow/nodes/vector_db.py,sha256=t6I17q6iR3yQreiDHpRrksMdWDPIvgqJs076z-7dlQQ,5712
61
+ vectorvein/workflow/nodes/vector_db.py,sha256=p9AT_E8ASbcYHZqHYTCIGvqkIqzxaFM4UxaUELJEe-c,6112
62
62
  vectorvein/workflow/nodes/video_generation.py,sha256=qmdg-t_idpxq1veukd-jv_ChICMOoInKxprV9Z4Vi2w,4118
63
- vectorvein/workflow/nodes/web_crawlers.py,sha256=BhJBX1AZH7-22Gu95Ox4qJqmH5DU-m4dbUb5N5DTA-M,5559
64
- vectorvein/workflow/utils/check.py,sha256=N2eHyZZVCX_fFriK4pcdDShTCwaLNDngkC_247kF3-c,6836
63
+ vectorvein/workflow/nodes/web_crawlers.py,sha256=FB0bTimkk___p3Z5UwQx2YarJyQCc45jjnbXbgGA_qw,5640
64
+ vectorvein/workflow/utils/check.py,sha256=Oj_S5WQf4_Fr_ro3ipjZt9unKFSFcuwZrrSmrS9kVLE,10193
65
65
  vectorvein/workflow/utils/json_to_code.py,sha256=F7dhDy8kGc8ndOeihGLRLGFGlquoxVlb02ENtxnQ0C8,5914
66
66
  vectorvein/workflow/utils/layout.py,sha256=j0bRD3uaXu40xCS6U6BGahBI8FrHa5MiF55GbTrZ1LM,4565
67
- vectorvein-0.2.55.dist-info/RECORD,,
67
+ vectorvein-0.2.57.dist-info/RECORD,,