vectorvein 0.1.80__py3-none-any.whl → 0.1.81__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.
- vectorvein/workflow/graph/edge.py +36 -0
- vectorvein/workflow/graph/node.py +82 -0
- vectorvein/workflow/graph/port.py +173 -0
- vectorvein/workflow/graph/workflow.py +87 -0
- vectorvein/workflow/nodes/__init__.py +136 -0
- vectorvein/workflow/nodes/audio_generation.py +154 -0
- vectorvein/workflow/nodes/control_flows.py +170 -0
- vectorvein/workflow/nodes/file_processing.py +106 -0
- vectorvein/workflow/nodes/image_generation.py +743 -0
- vectorvein/workflow/nodes/llms.py +802 -0
- vectorvein/workflow/nodes/media_editing.py +668 -0
- vectorvein/workflow/nodes/media_processing.py +478 -0
- vectorvein/workflow/nodes/output.py +357 -0
- vectorvein/workflow/nodes/relational_db.py +153 -0
- vectorvein/workflow/nodes/text_processing.py +218 -0
- vectorvein/workflow/nodes/tools.py +331 -0
- vectorvein/workflow/nodes/triggers.py +0 -0
- vectorvein/workflow/nodes/vector_db.py +156 -0
- vectorvein/workflow/nodes/video_generation.py +113 -0
- vectorvein/workflow/nodes/web_crawlers.py +157 -0
- vectorvein/workflow/utils/json_to_code.py +191 -0
- {vectorvein-0.1.80.dist-info → vectorvein-0.1.81.dist-info}/METADATA +1 -1
- {vectorvein-0.1.80.dist-info → vectorvein-0.1.81.dist-info}/RECORD +25 -4
- {vectorvein-0.1.80.dist-info → vectorvein-0.1.81.dist-info}/WHEEL +0 -0
- {vectorvein-0.1.80.dist-info → vectorvein-0.1.81.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from ..graph.node import Node
|
4
|
+
from ..graph.port import PortType, InputPort, OutputPort
|
5
|
+
|
6
|
+
|
7
|
+
class VectorDbAddData(Node):
|
8
|
+
def __init__(self, id: Optional[str] = None):
|
9
|
+
super().__init__(
|
10
|
+
node_type="AddData",
|
11
|
+
category="vector_db",
|
12
|
+
task_name="vector_db.add_data",
|
13
|
+
node_id=id,
|
14
|
+
ports={
|
15
|
+
"text": InputPort(
|
16
|
+
name="text",
|
17
|
+
port_type=PortType.INPUT,
|
18
|
+
value="",
|
19
|
+
),
|
20
|
+
"content_title": InputPort(
|
21
|
+
name="content_title",
|
22
|
+
port_type=PortType.INPUT,
|
23
|
+
value="",
|
24
|
+
),
|
25
|
+
"source_url": InputPort(
|
26
|
+
name="source_url",
|
27
|
+
port_type=PortType.INPUT,
|
28
|
+
value="",
|
29
|
+
),
|
30
|
+
"database": InputPort(
|
31
|
+
name="database",
|
32
|
+
port_type=PortType.SELECT,
|
33
|
+
value="",
|
34
|
+
options=[],
|
35
|
+
),
|
36
|
+
"data_type": InputPort(
|
37
|
+
name="data_type",
|
38
|
+
port_type=PortType.SELECT,
|
39
|
+
value="text",
|
40
|
+
options=[
|
41
|
+
{"value": "TEXT", "label": "Text"},
|
42
|
+
],
|
43
|
+
),
|
44
|
+
"split_method": InputPort(
|
45
|
+
name="split_method",
|
46
|
+
port_type=PortType.SELECT,
|
47
|
+
value="general",
|
48
|
+
options=[
|
49
|
+
{"value": "general", "label": "general"},
|
50
|
+
{"value": "delimiter", "label": "delimiter"},
|
51
|
+
{"value": "markdown", "label": "markdown"},
|
52
|
+
{"value": "table", "label": "table"},
|
53
|
+
],
|
54
|
+
condition="return fieldsData.data_type.value == 'text'",
|
55
|
+
),
|
56
|
+
"chunk_length": InputPort(
|
57
|
+
name="chunk_length",
|
58
|
+
port_type=PortType.NUMBER,
|
59
|
+
value=500,
|
60
|
+
condition="return ['general', 'markdown'].includes(fieldsData.split_method.value)",
|
61
|
+
),
|
62
|
+
"chunk_overlap": InputPort(
|
63
|
+
name="chunk_overlap",
|
64
|
+
port_type=PortType.NUMBER,
|
65
|
+
value=30,
|
66
|
+
condition="return ['general', 'markdown'].includes(fieldsData.split_method.value)",
|
67
|
+
),
|
68
|
+
"delimiter": InputPort(
|
69
|
+
name="delimiter",
|
70
|
+
port_type=PortType.INPUT,
|
71
|
+
value="\\n",
|
72
|
+
condition="return fieldsData.split_method.value == 'delimiter'",
|
73
|
+
),
|
74
|
+
"remove_url_and_email": InputPort(
|
75
|
+
name="remove_url_and_email",
|
76
|
+
port_type=PortType.CHECKBOX,
|
77
|
+
value=True,
|
78
|
+
),
|
79
|
+
"wait_for_processing": InputPort(
|
80
|
+
name="wait_for_processing",
|
81
|
+
port_type=PortType.CHECKBOX,
|
82
|
+
value=False,
|
83
|
+
),
|
84
|
+
"object_id": OutputPort(name="object_id"),
|
85
|
+
},
|
86
|
+
)
|
87
|
+
|
88
|
+
|
89
|
+
class VectorDbDeleteData(Node):
|
90
|
+
def __init__(self, id: Optional[str] = None):
|
91
|
+
super().__init__(
|
92
|
+
node_type="DeleteData",
|
93
|
+
category="vector_db",
|
94
|
+
task_name="vector_db.delete_data",
|
95
|
+
node_id=id,
|
96
|
+
ports={
|
97
|
+
"object_id": InputPort(
|
98
|
+
name="object_id",
|
99
|
+
port_type=PortType.INPUT,
|
100
|
+
value="",
|
101
|
+
),
|
102
|
+
"database": InputPort(
|
103
|
+
name="database",
|
104
|
+
port_type=PortType.SELECT,
|
105
|
+
value="",
|
106
|
+
options=[],
|
107
|
+
),
|
108
|
+
"delete_success": OutputPort(name="delete_success", port_type=PortType.CHECKBOX),
|
109
|
+
},
|
110
|
+
)
|
111
|
+
|
112
|
+
|
113
|
+
class VectorDbSearchData(Node):
|
114
|
+
def __init__(self, id: Optional[str] = None):
|
115
|
+
super().__init__(
|
116
|
+
node_type="SearchData",
|
117
|
+
category="vector_db",
|
118
|
+
task_name="vector_db.search_data",
|
119
|
+
node_id=id,
|
120
|
+
ports={
|
121
|
+
"search_text": InputPort(
|
122
|
+
name="search_text",
|
123
|
+
port_type=PortType.TEXT,
|
124
|
+
value="",
|
125
|
+
),
|
126
|
+
"data_type": InputPort(
|
127
|
+
name="data_type",
|
128
|
+
port_type=PortType.SELECT,
|
129
|
+
value="text",
|
130
|
+
options=[
|
131
|
+
{"value": "text", "label": "Text"},
|
132
|
+
],
|
133
|
+
),
|
134
|
+
"database": InputPort(
|
135
|
+
name="database",
|
136
|
+
port_type=PortType.SELECT,
|
137
|
+
value="",
|
138
|
+
options=[],
|
139
|
+
),
|
140
|
+
"count": InputPort(
|
141
|
+
name="count",
|
142
|
+
port_type=PortType.NUMBER,
|
143
|
+
value=5,
|
144
|
+
),
|
145
|
+
"output_type": InputPort(
|
146
|
+
name="output_type",
|
147
|
+
port_type=PortType.SELECT,
|
148
|
+
value="text",
|
149
|
+
options=[
|
150
|
+
{"value": "text", "label": "Text"},
|
151
|
+
{"value": "list", "label": "List"},
|
152
|
+
],
|
153
|
+
),
|
154
|
+
"output": OutputPort(),
|
155
|
+
},
|
156
|
+
)
|
@@ -0,0 +1,113 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from ..graph.node import Node
|
4
|
+
from ..graph.port import PortType, InputPort, OutputPort
|
5
|
+
|
6
|
+
|
7
|
+
class KlingVideo(Node):
|
8
|
+
def __init__(self, id: Optional[str] = None):
|
9
|
+
super().__init__(
|
10
|
+
node_type="KlingVideo",
|
11
|
+
category="video_generation",
|
12
|
+
task_name="video_generation.kling_video",
|
13
|
+
node_id=id,
|
14
|
+
ports={
|
15
|
+
"prompt": InputPort(
|
16
|
+
name="prompt",
|
17
|
+
port_type=PortType.TEXTAREA,
|
18
|
+
value="",
|
19
|
+
),
|
20
|
+
"image": InputPort(
|
21
|
+
name="image",
|
22
|
+
port_type=PortType.FILE,
|
23
|
+
value=list(),
|
24
|
+
support_file_types=[".jpg", ".jpeg", ".png"],
|
25
|
+
multiple=True,
|
26
|
+
),
|
27
|
+
"duration": InputPort(
|
28
|
+
name="duration",
|
29
|
+
port_type=PortType.SELECT,
|
30
|
+
value=5,
|
31
|
+
options=[
|
32
|
+
{"value": 5, "label": "5"},
|
33
|
+
{"value": 10, "label": "10"},
|
34
|
+
],
|
35
|
+
),
|
36
|
+
"aspect_ratio": InputPort(
|
37
|
+
name="aspect_ratio",
|
38
|
+
port_type=PortType.SELECT,
|
39
|
+
value="16:9",
|
40
|
+
options=[
|
41
|
+
{"value": "16:9", "label": "16:9"},
|
42
|
+
{"value": "9:16", "label": "9:16"},
|
43
|
+
{"value": "1:1", "label": "1:1"},
|
44
|
+
],
|
45
|
+
),
|
46
|
+
"model": InputPort(
|
47
|
+
name="model",
|
48
|
+
port_type=PortType.SELECT,
|
49
|
+
value="v1_standard",
|
50
|
+
options=[
|
51
|
+
{"value": "v1_pro", "label": "v1_pro"},
|
52
|
+
{"value": "v1_standard", "label": "v1_standard"},
|
53
|
+
],
|
54
|
+
),
|
55
|
+
"output_type": InputPort(
|
56
|
+
name="output_type",
|
57
|
+
port_type=PortType.SELECT,
|
58
|
+
value="only_link",
|
59
|
+
options=[
|
60
|
+
{"value": "only_link", "label": "only_link"},
|
61
|
+
{"value": "html", "label": "html"},
|
62
|
+
],
|
63
|
+
),
|
64
|
+
"output": OutputPort(),
|
65
|
+
},
|
66
|
+
)
|
67
|
+
|
68
|
+
|
69
|
+
class CogVideoX(Node):
|
70
|
+
def __init__(self, id: Optional[str] = None):
|
71
|
+
super().__init__(
|
72
|
+
node_type="CogVideoX",
|
73
|
+
category="video_generation",
|
74
|
+
task_name="video_generation.cog_video_x",
|
75
|
+
node_id=id,
|
76
|
+
ports={
|
77
|
+
"prompt": InputPort(
|
78
|
+
name="prompt",
|
79
|
+
port_type=PortType.TEXTAREA,
|
80
|
+
value="",
|
81
|
+
),
|
82
|
+
"image": InputPort(
|
83
|
+
name="image",
|
84
|
+
port_type=PortType.FILE,
|
85
|
+
value=list(),
|
86
|
+
support_file_types=[".jpg", ".jpeg", ".png"],
|
87
|
+
multiple=True,
|
88
|
+
),
|
89
|
+
"auto_crop": InputPort(
|
90
|
+
name="auto_crop",
|
91
|
+
port_type=PortType.CHECKBOX,
|
92
|
+
value=True,
|
93
|
+
),
|
94
|
+
"model": InputPort(
|
95
|
+
name="model",
|
96
|
+
port_type=PortType.SELECT,
|
97
|
+
value="cogvideox",
|
98
|
+
options=[
|
99
|
+
{"value": "cogvideox", "label": "cogvideox"},
|
100
|
+
],
|
101
|
+
),
|
102
|
+
"output_type": InputPort(
|
103
|
+
name="output_type",
|
104
|
+
port_type=PortType.SELECT,
|
105
|
+
value="only_link",
|
106
|
+
options=[
|
107
|
+
{"value": "only_link", "label": "only_link"},
|
108
|
+
{"value": "html", "label": "html"},
|
109
|
+
],
|
110
|
+
),
|
111
|
+
"output": OutputPort(),
|
112
|
+
},
|
113
|
+
)
|
@@ -0,0 +1,157 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from ..graph.node import Node
|
4
|
+
from ..graph.port import PortType, InputPort, OutputPort
|
5
|
+
|
6
|
+
|
7
|
+
class TextCrawler(Node):
|
8
|
+
def __init__(self, id: Optional[str] = None):
|
9
|
+
super().__init__(
|
10
|
+
node_type="TextCrawler",
|
11
|
+
category="web_crawlers",
|
12
|
+
task_name="web_crawlers.text_crawler",
|
13
|
+
node_id=id,
|
14
|
+
ports={
|
15
|
+
"url": InputPort(
|
16
|
+
name="url",
|
17
|
+
port_type=PortType.INPUT,
|
18
|
+
value="",
|
19
|
+
),
|
20
|
+
"output_type": InputPort(
|
21
|
+
name="output_type",
|
22
|
+
port_type=PortType.SELECT,
|
23
|
+
value="text",
|
24
|
+
options=[
|
25
|
+
{"value": "text", "label": "Text"},
|
26
|
+
{"value": "html", "label": "HTML"},
|
27
|
+
],
|
28
|
+
),
|
29
|
+
"use_oversea_crawler": InputPort(
|
30
|
+
name="use_oversea_crawler",
|
31
|
+
port_type=PortType.CHECKBOX,
|
32
|
+
value=False,
|
33
|
+
),
|
34
|
+
"output_title": OutputPort(
|
35
|
+
name="output_title",
|
36
|
+
),
|
37
|
+
"output_text": OutputPort(
|
38
|
+
name="output_text",
|
39
|
+
),
|
40
|
+
},
|
41
|
+
)
|
42
|
+
|
43
|
+
|
44
|
+
class BilibiliCrawler(Node):
|
45
|
+
def __init__(self, id: Optional[str] = None):
|
46
|
+
super().__init__(
|
47
|
+
node_type="BilibiliCrawler",
|
48
|
+
category="web_crawlers",
|
49
|
+
task_name="web_crawlers.bilibili_crawler",
|
50
|
+
node_id=id,
|
51
|
+
ports={
|
52
|
+
"url_or_bvid": InputPort(
|
53
|
+
name="url_or_bvid",
|
54
|
+
port_type=PortType.INPUT,
|
55
|
+
value="",
|
56
|
+
),
|
57
|
+
"download_video": InputPort(
|
58
|
+
name="download_video",
|
59
|
+
port_type=PortType.CHECKBOX,
|
60
|
+
value=False,
|
61
|
+
),
|
62
|
+
"output_type": InputPort(
|
63
|
+
name="output_type",
|
64
|
+
port_type=PortType.SELECT,
|
65
|
+
value="str",
|
66
|
+
options=[
|
67
|
+
{"value": "str", "label": "str"},
|
68
|
+
{"value": "list", "label": "list"},
|
69
|
+
],
|
70
|
+
),
|
71
|
+
"output_title": OutputPort(
|
72
|
+
name="output_title",
|
73
|
+
),
|
74
|
+
"output_subtitle": OutputPort(
|
75
|
+
name="output_subtitle",
|
76
|
+
),
|
77
|
+
"output_video": OutputPort(
|
78
|
+
name="output_video",
|
79
|
+
),
|
80
|
+
},
|
81
|
+
)
|
82
|
+
|
83
|
+
|
84
|
+
class DouyinCrawler(Node):
|
85
|
+
def __init__(self, id: Optional[str] = None):
|
86
|
+
super().__init__(
|
87
|
+
node_type="DouyinCrawler",
|
88
|
+
category="web_crawlers",
|
89
|
+
task_name="web_crawlers.douyin_crawler",
|
90
|
+
node_id=id,
|
91
|
+
ports={
|
92
|
+
"url": InputPort(
|
93
|
+
name="url",
|
94
|
+
port_type=PortType.INPUT,
|
95
|
+
value="",
|
96
|
+
),
|
97
|
+
"output_title": OutputPort(
|
98
|
+
name="output_title",
|
99
|
+
),
|
100
|
+
"output_video": OutputPort(
|
101
|
+
name="output_video",
|
102
|
+
),
|
103
|
+
"output_audio": OutputPort(
|
104
|
+
name="output_audio",
|
105
|
+
),
|
106
|
+
},
|
107
|
+
)
|
108
|
+
|
109
|
+
|
110
|
+
class YoutubeCrawler(Node):
|
111
|
+
def __init__(self, id: Optional[str] = None):
|
112
|
+
super().__init__(
|
113
|
+
node_type="YoutubeCrawler",
|
114
|
+
category="web_crawlers",
|
115
|
+
task_name="web_crawlers.youtube_crawler",
|
116
|
+
node_id=id,
|
117
|
+
ports={
|
118
|
+
"url_or_video_id": InputPort(
|
119
|
+
name="url_or_video_id",
|
120
|
+
port_type=PortType.INPUT,
|
121
|
+
value="",
|
122
|
+
),
|
123
|
+
"get_comments": InputPort(
|
124
|
+
name="get_comments",
|
125
|
+
port_type=PortType.CHECKBOX,
|
126
|
+
value=False,
|
127
|
+
),
|
128
|
+
"comments_type": InputPort(
|
129
|
+
name="comments_type",
|
130
|
+
port_type=PortType.RADIO,
|
131
|
+
value="text_only",
|
132
|
+
options=[
|
133
|
+
{"value": "text_only", "label": "text_only"},
|
134
|
+
{"value": "detailed", "label": "detailed"},
|
135
|
+
],
|
136
|
+
condition="return fieldsData.get_comments.value",
|
137
|
+
),
|
138
|
+
"output_type": InputPort(
|
139
|
+
name="output_type",
|
140
|
+
port_type=PortType.SELECT,
|
141
|
+
value="str",
|
142
|
+
options=[
|
143
|
+
{"value": "str", "label": "str"},
|
144
|
+
{"value": "list", "label": "list"},
|
145
|
+
],
|
146
|
+
),
|
147
|
+
"output_title": OutputPort(
|
148
|
+
name="output_title",
|
149
|
+
),
|
150
|
+
"output_subtitle": OutputPort(
|
151
|
+
name="output_subtitle",
|
152
|
+
),
|
153
|
+
"output_comments": OutputPort(
|
154
|
+
name="output_comments",
|
155
|
+
),
|
156
|
+
},
|
157
|
+
)
|
@@ -0,0 +1,191 @@
|
|
1
|
+
import sys
|
2
|
+
import json
|
3
|
+
import importlib
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Optional, Union
|
6
|
+
|
7
|
+
|
8
|
+
def _get_workflow_package_path():
|
9
|
+
"""
|
10
|
+
获取workflow包的根路径
|
11
|
+
|
12
|
+
Returns:
|
13
|
+
workflow包的根路径
|
14
|
+
"""
|
15
|
+
# 获取当前文件的绝对路径
|
16
|
+
current_file = Path(__file__).resolve()
|
17
|
+
# workflow包的根路径应该是 workflow 目录的父目录
|
18
|
+
package_root = current_file.parent.parent.parent
|
19
|
+
return str(package_root)
|
20
|
+
|
21
|
+
|
22
|
+
def _safe_import_node_class(category: str, node_type: str):
|
23
|
+
"""
|
24
|
+
安全地动态导入节点类
|
25
|
+
|
26
|
+
Args:
|
27
|
+
category: 节点类别
|
28
|
+
node_type: 节点类型
|
29
|
+
|
30
|
+
Returns:
|
31
|
+
导入的类或None
|
32
|
+
"""
|
33
|
+
try:
|
34
|
+
# 确保workflow包路径在sys.path中
|
35
|
+
package_root = _get_workflow_package_path()
|
36
|
+
if package_root not in sys.path:
|
37
|
+
sys.path.insert(0, package_root)
|
38
|
+
|
39
|
+
module = importlib.import_module(f"vectorvein.workflow.nodes.{category}")
|
40
|
+
return getattr(module, node_type)
|
41
|
+
except (ImportError, AttributeError) as e:
|
42
|
+
print(f"Warning: Failed to import {node_type} from {category}: {e}")
|
43
|
+
return None
|
44
|
+
|
45
|
+
|
46
|
+
def to_python_str(value):
|
47
|
+
if isinstance(value, str):
|
48
|
+
value = value.replace("\n", "\\n")
|
49
|
+
value = f'"{value}"'
|
50
|
+
return value
|
51
|
+
|
52
|
+
|
53
|
+
def generate_python_code(
|
54
|
+
json_str: Optional[str] = None,
|
55
|
+
json_file: Optional[Union[str, Path]] = None,
|
56
|
+
skip_trigger: bool = True,
|
57
|
+
skip_import: bool = False,
|
58
|
+
) -> str:
|
59
|
+
"""
|
60
|
+
将工作流JSON文件转换为Python代码
|
61
|
+
|
62
|
+
Args:
|
63
|
+
json_str: JSON字符串
|
64
|
+
json_file: JSON文件路径
|
65
|
+
skip_trigger: 是否跳过触发器节点
|
66
|
+
skip_import: 是否跳过导入语句
|
67
|
+
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
生成的Python代码字符串
|
71
|
+
"""
|
72
|
+
# 读取JSON文件
|
73
|
+
if json_file:
|
74
|
+
with open(json_file, "r", encoding="utf8") as f:
|
75
|
+
workflow_data = json.load(f)
|
76
|
+
elif json_str:
|
77
|
+
workflow_data = json.loads(json_str)
|
78
|
+
else:
|
79
|
+
raise ValueError("json_file or json_str must be provided")
|
80
|
+
|
81
|
+
code = []
|
82
|
+
if not skip_import:
|
83
|
+
code.append("from vectorvein.workflow.graph.workflow import Workflow")
|
84
|
+
|
85
|
+
# 收集需要导入的节点类
|
86
|
+
node_imports = set()
|
87
|
+
node_instances = {}
|
88
|
+
|
89
|
+
# 解析节点并生成导入语句
|
90
|
+
for node in workflow_data["nodes"]:
|
91
|
+
node_type = node["type"]
|
92
|
+
category = node["category"]
|
93
|
+
if skip_trigger and category == "triggers":
|
94
|
+
continue
|
95
|
+
|
96
|
+
if category == "assistedNodes":
|
97
|
+
continue
|
98
|
+
|
99
|
+
category, task_name = node["data"]["task_name"].split(".")
|
100
|
+
|
101
|
+
# 动态导入节点类
|
102
|
+
NodeClass = _safe_import_node_class(category, node_type)
|
103
|
+
if NodeClass is None:
|
104
|
+
continue
|
105
|
+
|
106
|
+
node_imports.add(f"from vectorvein.workflow.nodes.{category} import {node_type}")
|
107
|
+
|
108
|
+
# 创建节点实例以获取默认值
|
109
|
+
node_instance = NodeClass()
|
110
|
+
|
111
|
+
add_ports = []
|
112
|
+
show_ports = []
|
113
|
+
values = []
|
114
|
+
for port_name, port in node["data"]["template"].items():
|
115
|
+
if port_name not in node_instance.ports:
|
116
|
+
add_ports.append(port)
|
117
|
+
continue
|
118
|
+
|
119
|
+
if port["show"]:
|
120
|
+
show_ports.append(port["name"])
|
121
|
+
|
122
|
+
# 比较端口值与默认值
|
123
|
+
port_value = port["value"]
|
124
|
+
default_value = node_instance.ports[port_name].value if port_name in node_instance.ports else None
|
125
|
+
|
126
|
+
if port_value and port_value != default_value:
|
127
|
+
values.append(port)
|
128
|
+
|
129
|
+
node_instances[node["id"]] = {
|
130
|
+
"var_name": f"{task_name}_{len(node_instances)}",
|
131
|
+
"type": node_type,
|
132
|
+
"show_ports": show_ports,
|
133
|
+
"values": values,
|
134
|
+
"add_ports": add_ports,
|
135
|
+
}
|
136
|
+
|
137
|
+
# 添加导入语句
|
138
|
+
if not skip_import:
|
139
|
+
code.extend(sorted(list(node_imports)))
|
140
|
+
code.append("")
|
141
|
+
|
142
|
+
# 生成节点实例化代码
|
143
|
+
for info in node_instances.values():
|
144
|
+
code.append(f"{info['var_name']} = {info['type']}()")
|
145
|
+
|
146
|
+
code.append("")
|
147
|
+
code.append("workflow = Workflow()")
|
148
|
+
|
149
|
+
# 添加节点到工作流
|
150
|
+
node_list = [f" {info['var_name']}," for info in node_instances.values()]
|
151
|
+
code.append(f"workflow.add_nodes([\n{'\n'.join(node_list)}\n])")
|
152
|
+
|
153
|
+
code.append("")
|
154
|
+
for info in node_instances.values():
|
155
|
+
for port in info["add_ports"]:
|
156
|
+
params = [
|
157
|
+
f"name={to_python_str(port['name'])}",
|
158
|
+
f"port_type={to_python_str(port['field_type'])}",
|
159
|
+
f"value={to_python_str(port['value'])}",
|
160
|
+
]
|
161
|
+
if port["show"]:
|
162
|
+
params.append(f"show={port['show']}")
|
163
|
+
if port["options"]:
|
164
|
+
params.append(f"options={port['options']}")
|
165
|
+
if port["is_output"]:
|
166
|
+
params.append(f"is_output={bool(port['is_output'])}")
|
167
|
+
code.append(f"{info['var_name']}.add_port({', '.join(params)})")
|
168
|
+
|
169
|
+
for port_name in info["show_ports"]:
|
170
|
+
code.append(f"{info['var_name']}.ports['{port_name}'].show = True")
|
171
|
+
|
172
|
+
for port in info["values"]:
|
173
|
+
code.append(f"{info['var_name']}.ports['{port['name']}'].value = {to_python_str(port['value'])}")
|
174
|
+
|
175
|
+
code.append("")
|
176
|
+
|
177
|
+
# 生成边的连接代码
|
178
|
+
for edge in workflow_data["edges"]:
|
179
|
+
source_var = node_instances[edge["source"]]["var_name"]
|
180
|
+
target_var = node_instances[edge["target"]]["var_name"]
|
181
|
+
source_handle = edge["sourceHandle"]
|
182
|
+
target_handle = edge["targetHandle"]
|
183
|
+
code.append(f'workflow.connect({source_var}, "{source_handle}", {target_var}, "{target_handle}")')
|
184
|
+
|
185
|
+
return "\n".join(code)
|
186
|
+
|
187
|
+
|
188
|
+
if __name__ == "__main__":
|
189
|
+
# 使用示例
|
190
|
+
code = generate_python_code(json_file="workflow.json")
|
191
|
+
print(code)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
vectorvein-0.1.
|
2
|
-
vectorvein-0.1.
|
3
|
-
vectorvein-0.1.
|
1
|
+
vectorvein-0.1.81.dist-info/METADATA,sha256=tk_zSkj8F29hPfBVkiQ43zBAW6EOY_9ookvC5Y8qtkA,641
|
2
|
+
vectorvein-0.1.81.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
3
|
+
vectorvein-0.1.81.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
4
4
|
vectorvein/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
vectorvein/chat_clients/__init__.py,sha256=omQuG4PRRPNflSAgtdU--rwsWG6vMpwMEyIGZyFVHVQ,18596
|
6
6
|
vectorvein/chat_clients/anthropic_client.py,sha256=PGIKldH4FnGrqozoY_FZ6LqhDHC-jY7NF5J1F1zT2Ok,38257
|
@@ -33,4 +33,25 @@ vectorvein/types/llm_parameters.py,sha256=CLhDSp9KI_zzjIXUvjiTuGxfYXpubTNBCVcJ6R
|
|
33
33
|
vectorvein/types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
vectorvein/utilities/media_processing.py,sha256=CTRq-lGlFkFgP_FSRhNwF_qUgmOrXPf2_1Ok9HY42_g,5887
|
35
35
|
vectorvein/utilities/retry.py,sha256=6KFS9R2HdhqM3_9jkjD4F36ZSpEx2YNFGOVlpOsUetM,2208
|
36
|
-
vectorvein
|
36
|
+
vectorvein/workflow/graph/edge.py,sha256=xLZEJmBjAfVB53cd7CuRcKhgE6QqXv9nz32wJn8cmyk,1064
|
37
|
+
vectorvein/workflow/graph/node.py,sha256=nxDq4pTFcsm2x9MmNmZxghhc-HduSLRwH3Ct2i8bZ3o,2871
|
38
|
+
vectorvein/workflow/graph/port.py,sha256=kv0YbAPqe9Hh9QPSoiB2PUTTWQT1xIdNeVD50OkWTzA,5684
|
39
|
+
vectorvein/workflow/graph/workflow.py,sha256=BmS351-WSeHQ02Kh0jOQpxJbNgZ-AHwW0mSQLXcKceU,2805
|
40
|
+
vectorvein/workflow/nodes/__init__.py,sha256=AB8YCjkK3xdpk1_jfzsBkDtsSp48RcS_N4631MyEJXU,3159
|
41
|
+
vectorvein/workflow/nodes/audio_generation.py,sha256=ht2S0vnd0mIAt6FBaSWlADGbb7f_1DAySYrgYnvZT1Q,5726
|
42
|
+
vectorvein/workflow/nodes/control_flows.py,sha256=Zc_uWuroYznLrU-BZCncyzvejC-zFl6EuN_VP8oq5mY,6573
|
43
|
+
vectorvein/workflow/nodes/file_processing.py,sha256=Rsjc8al0z-2KuweO0nIybWvceqxbqOPQyTs0-pgy5m4,3980
|
44
|
+
vectorvein/workflow/nodes/image_generation.py,sha256=fXOhLGodJ3OdKBPXO5a3rq4wN2GMJ0jwqKO_gJFdocU,32852
|
45
|
+
vectorvein/workflow/nodes/llms.py,sha256=MU0tmCOcPUcN4uVI9t5RlQeCuKgiXzVNxpdtgMzLV2U,31077
|
46
|
+
vectorvein/workflow/nodes/media_editing.py,sha256=Od0X0SdcyRhcJckWpDM4WvgWEKxaIsgMXpMifN8Sc5M,29405
|
47
|
+
vectorvein/workflow/nodes/media_processing.py,sha256=t-azYDphXmLRdOyHDfXFTS1tsEOyKqKskDyD0y232j8,19043
|
48
|
+
vectorvein/workflow/nodes/output.py,sha256=_UQxiddHtGv2rkjhUFE-KDgrjnh0AGJQJyq9-4Aji5A,12567
|
49
|
+
vectorvein/workflow/nodes/relational_db.py,sha256=zfzUhV25TpZGhkIzO18PmAT5xhcsJC4AXKy0zyA05w8,5408
|
50
|
+
vectorvein/workflow/nodes/text_processing.py,sha256=cfepHoy8JaFDqWLUzl6lmlDlKaH0vk1gWQSm7T0wmn8,7503
|
51
|
+
vectorvein/workflow/nodes/tools.py,sha256=Vw7yPdPqENqQ-MwbPcz5LQ-5036UGApCPX6ZspPOw40,12739
|
52
|
+
vectorvein/workflow/nodes/triggers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
+
vectorvein/workflow/nodes/vector_db.py,sha256=FG0fDc99wYLrxqchcbnTKyyFPrVjw710pld--F_j9Oo,5744
|
54
|
+
vectorvein/workflow/nodes/video_generation.py,sha256=qmdg-t_idpxq1veukd-jv_ChICMOoInKxprV9Z4Vi2w,4118
|
55
|
+
vectorvein/workflow/nodes/web_crawlers.py,sha256=LsqomfXfqrXfHJDO1cl0Ox48f4St7X_SL12DSbAMSOw,5415
|
56
|
+
vectorvein/workflow/utils/json_to_code.py,sha256=8e08bThiXTGXXI0GuBde6lMSp4-CHt7B5S_6rQ3hkg0,6020
|
57
|
+
vectorvein-0.1.81.dist-info/RECORD,,
|
File without changes
|
File without changes
|