service-forge 0.1.0__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.
- service_forge/api/http_api.py +138 -0
- service_forge/api/kafka_api.py +126 -0
- service_forge/api/task_manager.py +141 -0
- service_forge/api/websocket_api.py +86 -0
- service_forge/api/websocket_manager.py +425 -0
- service_forge/db/__init__.py +1 -0
- service_forge/db/database.py +119 -0
- service_forge/llm/__init__.py +62 -0
- service_forge/llm/llm.py +56 -0
- service_forge/main.py +121 -0
- service_forge/model/__init__.py +0 -0
- service_forge/model/websocket.py +13 -0
- service_forge/proto/foo_input.py +5 -0
- service_forge/service.py +111 -0
- service_forge/service_config.py +115 -0
- service_forge/sft/cli.py +91 -0
- service_forge/sft/cmd/config_command.py +67 -0
- service_forge/sft/cmd/deploy_service.py +124 -0
- service_forge/sft/cmd/list_tars.py +41 -0
- service_forge/sft/cmd/service_command.py +149 -0
- service_forge/sft/cmd/upload_service.py +36 -0
- service_forge/sft/config/injector.py +87 -0
- service_forge/sft/config/injector_default_files.py +97 -0
- service_forge/sft/config/sf_metadata.py +30 -0
- service_forge/sft/config/sft_config.py +125 -0
- service_forge/sft/file/__init__.py +0 -0
- service_forge/sft/file/ignore_pattern.py +80 -0
- service_forge/sft/file/sft_file_manager.py +107 -0
- service_forge/sft/kubernetes/kubernetes_manager.py +257 -0
- service_forge/sft/util/assert_util.py +25 -0
- service_forge/sft/util/logger.py +16 -0
- service_forge/sft/util/name_util.py +2 -0
- service_forge/utils/__init__.py +0 -0
- service_forge/utils/default_type_converter.py +12 -0
- service_forge/utils/register.py +39 -0
- service_forge/utils/type_converter.py +74 -0
- service_forge/workflow/__init__.py +1 -0
- service_forge/workflow/context.py +13 -0
- service_forge/workflow/edge.py +31 -0
- service_forge/workflow/node.py +179 -0
- service_forge/workflow/nodes/__init__.py +7 -0
- service_forge/workflow/nodes/control/if_node.py +29 -0
- service_forge/workflow/nodes/input/console_input_node.py +26 -0
- service_forge/workflow/nodes/llm/query_llm_node.py +41 -0
- service_forge/workflow/nodes/nested/workflow_node.py +28 -0
- service_forge/workflow/nodes/output/kafka_output_node.py +27 -0
- service_forge/workflow/nodes/output/print_node.py +29 -0
- service_forge/workflow/nodes/test/if_console_input_node.py +33 -0
- service_forge/workflow/nodes/test/time_consuming_node.py +61 -0
- service_forge/workflow/port.py +86 -0
- service_forge/workflow/trigger.py +20 -0
- service_forge/workflow/triggers/__init__.py +4 -0
- service_forge/workflow/triggers/fast_api_trigger.py +125 -0
- service_forge/workflow/triggers/kafka_api_trigger.py +44 -0
- service_forge/workflow/triggers/once_trigger.py +20 -0
- service_forge/workflow/triggers/period_trigger.py +26 -0
- service_forge/workflow/workflow.py +251 -0
- service_forge/workflow/workflow_factory.py +227 -0
- service_forge/workflow/workflow_group.py +23 -0
- service_forge/workflow/workflow_type.py +52 -0
- service_forge-0.1.0.dist-info/METADATA +93 -0
- service_forge-0.1.0.dist-info/RECORD +64 -0
- service_forge-0.1.0.dist-info/WHEEL +4 -0
- service_forge-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from service_forge.workflow.workflow import Workflow
|
|
2
|
+
|
|
3
|
+
class WorkflowGroup:
|
|
4
|
+
def __init__(self, workflows: list[Workflow], main_workflow_name: str = "main") -> None:
|
|
5
|
+
self.workflows = workflows
|
|
6
|
+
self.main_workflow_name = main_workflow_name
|
|
7
|
+
|
|
8
|
+
def add_workflow(self, workflow: Workflow) -> None:
|
|
9
|
+
self.workflows.append(workflow)
|
|
10
|
+
|
|
11
|
+
def get_workflow(self, name: str) -> Workflow | None:
|
|
12
|
+
for workflow in self.workflows:
|
|
13
|
+
if workflow.name == name:
|
|
14
|
+
return workflow
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
async def run(self, name: str = None) -> None:
|
|
18
|
+
if name is None:
|
|
19
|
+
name = self.main_workflow_name
|
|
20
|
+
workflow = self.get_workflow(name)
|
|
21
|
+
if workflow is None:
|
|
22
|
+
raise ValueError(f"Workflow with name {name} not found in workflow group.")
|
|
23
|
+
await workflow.run()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
import importlib
|
|
4
|
+
import inspect
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Type, Any
|
|
7
|
+
|
|
8
|
+
from service_forge.utils.register import Register
|
|
9
|
+
|
|
10
|
+
class WorkflowType:
|
|
11
|
+
CLASS_NOT_REQUIRED_TO_REGISTER = ['WorkflowType']
|
|
12
|
+
|
|
13
|
+
def __init__(self, name: str, type: type) -> None:
|
|
14
|
+
self.name = name
|
|
15
|
+
self.type = type
|
|
16
|
+
|
|
17
|
+
def __init_subclass__(cls) -> None:
|
|
18
|
+
if cls.__name__ not in WorkflowType.CLASS_NOT_REQUIRED_TO_REGISTER:
|
|
19
|
+
workflow_type_register.register(cls.__name__, cls)
|
|
20
|
+
return super().__init_subclass__()
|
|
21
|
+
|
|
22
|
+
workflow_type_register = Register[WorkflowType]()
|
|
23
|
+
|
|
24
|
+
def _load_proto_classes():
|
|
25
|
+
# TODO: load from config
|
|
26
|
+
proto_dir = Path(__file__).parent.parent / "proto"
|
|
27
|
+
|
|
28
|
+
if not proto_dir.exists():
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
for py_file in proto_dir.glob("*.py"):
|
|
32
|
+
if py_file.name == "__init__.py":
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
module_name = py_file.stem
|
|
36
|
+
module_path = f"service_forge.proto.{module_name}"
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
module = importlib.import_module(module_path)
|
|
40
|
+
|
|
41
|
+
for name, obj in inspect.getmembers(module, inspect.isclass):
|
|
42
|
+
if (not name.startswith('_') and
|
|
43
|
+
obj.__module__ == module_path and
|
|
44
|
+
hasattr(obj, '__bases__')):
|
|
45
|
+
|
|
46
|
+
workflow_type = WorkflowType(name, obj)
|
|
47
|
+
workflow_type_register.register(name, workflow_type)
|
|
48
|
+
|
|
49
|
+
except Exception as e:
|
|
50
|
+
print(f"Failed to load module {module_path}: {e}")
|
|
51
|
+
|
|
52
|
+
_load_proto_classes()
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: service-forge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author-email: euxcet <zcc.qwer@gmail.com>
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: aiokafka>=0.12.0
|
|
8
|
+
Requires-Dist: alembic>=1.17.0
|
|
9
|
+
Requires-Dist: asyncpg>=0.30.0
|
|
10
|
+
Requires-Dist: dotenv>=0.9.9
|
|
11
|
+
Requires-Dist: fastapi>=0.119.1
|
|
12
|
+
Requires-Dist: greenlet>=3.2.4
|
|
13
|
+
Requires-Dist: jinja2>=3.1.6
|
|
14
|
+
Requires-Dist: kubernetes>=28.0.0
|
|
15
|
+
Requires-Dist: loguru>=0.7.3
|
|
16
|
+
Requires-Dist: omegaconf>=2.3.0
|
|
17
|
+
Requires-Dist: openai>=2.3.0
|
|
18
|
+
Requires-Dist: protobuf>=6.33.1
|
|
19
|
+
Requires-Dist: psycopg2-binary>=2.9.11
|
|
20
|
+
Requires-Dist: pydantic>=2.12.0
|
|
21
|
+
Requires-Dist: pytest-asyncio>=1.2.0
|
|
22
|
+
Requires-Dist: pytest>=8.4.2
|
|
23
|
+
Requires-Dist: python-dotenv>=1.1.1
|
|
24
|
+
Requires-Dist: python-jose>=3.5.0
|
|
25
|
+
Requires-Dist: python-multipart>=0.0.20
|
|
26
|
+
Requires-Dist: requests>=2.32.5
|
|
27
|
+
Requires-Dist: restrictedpython>=8.0
|
|
28
|
+
Requires-Dist: rich>=13.0.0
|
|
29
|
+
Requires-Dist: sqlalchemy>=2.0.44
|
|
30
|
+
Requires-Dist: typer>=0.12.0
|
|
31
|
+
Requires-Dist: uvicorn>=0.38.0
|
|
32
|
+
Requires-Dist: websockets>=15.0.1
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Service Forge
|
|
36
|
+
|
|
37
|
+
Automated service creation and maintenance tool.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## CLI Usage (sft)
|
|
46
|
+
|
|
47
|
+
Service Forge 提供了命令行工具 `sft` 用于服务管理。
|
|
48
|
+
|
|
49
|
+
### 服务上传和部署
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# 上传服务(打包并上传到服务器)
|
|
53
|
+
sft upload [project_path]
|
|
54
|
+
|
|
55
|
+
# 列出本地已打包的服务包
|
|
56
|
+
sft list
|
|
57
|
+
|
|
58
|
+
# 部署服务(只在服务器上使用)
|
|
59
|
+
sft deploy <name> <version>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 配置管理
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# 列出所有配置项
|
|
66
|
+
sft config list
|
|
67
|
+
|
|
68
|
+
# 获取指定配置项的值
|
|
69
|
+
sft config get <key>
|
|
70
|
+
|
|
71
|
+
# 设置配置项的值
|
|
72
|
+
sft config set <key> <value>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 服务管理
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 列出所有服务
|
|
79
|
+
sft service list
|
|
80
|
+
|
|
81
|
+
# 删除服务(只在服务器上使用)
|
|
82
|
+
sft service delete <service_name> [--force, -f]
|
|
83
|
+
|
|
84
|
+
# 查看服务日志(只在服务器上使用)
|
|
85
|
+
sft service logs <service_name> [--container, -c] [--tail, -n] [--follow, -f] [--previous, -p]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## TODO
|
|
89
|
+
|
|
90
|
+
- [x] 多次 trigger 并行执行
|
|
91
|
+
- [x] 支持 websocket 来做 trigger、输入和输出
|
|
92
|
+
- [x] 优化 websocket 客户端映射和重连支持
|
|
93
|
+
- [ ] 节点和 workflow 运行情况的回调函数
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
service_forge/main.py,sha256=IrYMcwwG9Y9kS7kTH9TS2e6DCiWQ2GeOoGoJAwftEtQ,3343
|
|
2
|
+
service_forge/service.py,sha256=xmQhtbYYsNb6yMYsZLlFkmWrNYB7rP5NWAwR_MKvHRs,4428
|
|
3
|
+
service_forge/service_config.py,sha256=wDZCldx6LIu5arq7kHnpVDHZbErCJlcHaiIrT3V2eRE,3620
|
|
4
|
+
service_forge/api/http_api.py,sha256=t2qXX7Zb5ZEI6LHiApT9XD0z5Dak1JZJJaD3CrYt_Xg,4899
|
|
5
|
+
service_forge/api/kafka_api.py,sha256=PInx2ZzKJRON7EaJFWroXkiOt_UeZY7WE6qK03gq4ak,4599
|
|
6
|
+
service_forge/api/task_manager.py,sha256=9Lk-NV4cBnuv9b8V6GVLWJJ4MCiAwCp5TVAwmYgqXbs,5269
|
|
7
|
+
service_forge/api/websocket_api.py,sha256=E36-fpUPxzMJ2YGlCPeqwRbryk2FMMbQD_pbb8k1FYI,3343
|
|
8
|
+
service_forge/api/websocket_manager.py,sha256=Xiwg3zwXRVi63sXmVH-TgbpL2XH_djyLeo96STm4cNM,16757
|
|
9
|
+
service_forge/db/__init__.py,sha256=vky6ZjFgPvBfLfwpwzm00rz6P86IOttKP0_UsbchBUw,47
|
|
10
|
+
service_forge/db/database.py,sha256=4xL-uuXXjLzvvcZ3NPQdQ1BEYMjz9PWD4S_mzWPEf-0,4489
|
|
11
|
+
service_forge/llm/__init__.py,sha256=9sB5uqp2F8AboYV4jAvOQfMkVMWM811sUxBahJJ-_fE,2868
|
|
12
|
+
service_forge/llm/llm.py,sha256=Sar99FkTPBJqkB6dwX81ww_hJp8cPYxlg7Go-zXPyg0,1865
|
|
13
|
+
service_forge/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
service_forge/model/websocket.py,sha256=YIUCW32sbHIEFPHjk5FiDM_rDe2aVD6OpzBQul2R5IM,267
|
|
15
|
+
service_forge/proto/foo_input.py,sha256=-POJZSIFrGdBGz7FqZZ03r5uztpc5Apin9A0Yxbk6YI,90
|
|
16
|
+
service_forge/sft/cli.py,sha256=stB_YPhZ7gAQeOxIq03-tLyl5VfU-gnRacAT05GSMis,2904
|
|
17
|
+
service_forge/sft/cmd/config_command.py,sha256=I9t2HG28S6lCXpExHyZUc47b_1yB3i51tCFVk5J6TTU,2382
|
|
18
|
+
service_forge/sft/cmd/deploy_service.py,sha256=riV5eSsNgcELgq1Wq53FX_lR8eLKPnQ94_Dyq7EP42w,4681
|
|
19
|
+
service_forge/sft/cmd/list_tars.py,sha256=Z3zvu2JLb_wNbTwi5TZXL5cZ8PxYrKks9AxkOzoUd_Q,1380
|
|
20
|
+
service_forge/sft/cmd/service_command.py,sha256=69GMMN61KtuoEFuYzFJ74ivNt8RX8q0I6rbePfJfEwQ,5538
|
|
21
|
+
service_forge/sft/cmd/upload_service.py,sha256=86PvvJSXCZKH4BU6rLytuc45grX-sRnQnOHCo9zUaPY,1232
|
|
22
|
+
service_forge/sft/config/injector.py,sha256=V4CcoGHinUW6ExTZKdy-gb4uOq3wXpc472k3aZtp19M,3555
|
|
23
|
+
service_forge/sft/config/injector_default_files.py,sha256=6CwuhqJHjfwz_V88CwHfE7jy13BFdhJaZBbN6cEI6UI,1849
|
|
24
|
+
service_forge/sft/config/sf_metadata.py,sha256=Y9akhSCgOd11-oqRs3LIs8FL9pvWNw6hyy57fuFcBhc,866
|
|
25
|
+
service_forge/sft/config/sft_config.py,sha256=zqZKNZMHNKaIbeKwUhHEYu0O4T6JA1z-4RURLX9jKa0,4539
|
|
26
|
+
service_forge/sft/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
+
service_forge/sft/file/ignore_pattern.py,sha256=UrVmR83wOx51XHFcZDTPp15dGYcvMTE5W1m07-SvHpw,2521
|
|
28
|
+
service_forge/sft/file/sft_file_manager.py,sha256=poIM77tZZg7vfwBdCsdQctBbCczVLQePdTwVINEABvE,4337
|
|
29
|
+
service_forge/sft/kubernetes/kubernetes_manager.py,sha256=IF2_X9U-k5Dx7EZuGrJ9lZ85ltbilrrZDfsl8qFyTu4,11339
|
|
30
|
+
service_forge/sft/util/assert_util.py,sha256=8HreVkOzs9_ClKiFqG4qsFn_yyDLo5uXYhYUPXlmDjM,828
|
|
31
|
+
service_forge/sft/util/logger.py,sha256=0Hi74IoxshE-wBgvBa2EZPXYj37tTrUYwlOBd9UMMMs,502
|
|
32
|
+
service_forge/sft/util/name_util.py,sha256=jQ4L6chyfESfsZI3z38gZcF79AE2Fn0-kUjG9ezobWQ,106
|
|
33
|
+
service_forge/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
service_forge/utils/default_type_converter.py,sha256=CuUZpMATdTwgcV1M3lbK64znwmEG85Zt3y_QGXr9tYQ,625
|
|
35
|
+
service_forge/utils/register.py,sha256=nxiGQBCX238FoZZhsDoDdBMv_2QzeIZpM367HPNfaqM,874
|
|
36
|
+
service_forge/utils/type_converter.py,sha256=zqkffSt-27eWcaxJGHxLnexqtXyzehTtPmITUfYT7-c,2402
|
|
37
|
+
service_forge/workflow/__init__.py,sha256=9oh4qPyA33RugrUYRAlLmFtmQPUN2wxruFQE3omTJF8,49
|
|
38
|
+
service_forge/workflow/context.py,sha256=E3z9nJZmrTqXy-9hswyHNmQyTEuGygryOBg_yfdH5xI,307
|
|
39
|
+
service_forge/workflow/edge.py,sha256=XPYSUGX_Cc0Rlamu1tuTFKjvySZa5IHVCeZN0uc9aYc,951
|
|
40
|
+
service_forge/workflow/node.py,sha256=WOCh75rDDrsoWqOEgguAnBfjvS15sXbai07GMsTvxHg,6413
|
|
41
|
+
service_forge/workflow/port.py,sha256=dMNSUTaOqB7u4lfJB6kQDUIUjXSA0tzwmKxnWCk0kgA,2659
|
|
42
|
+
service_forge/workflow/trigger.py,sha256=s7H4uD72jiX3ATh132FqGg8YK4bcekVPfXG0ELLhu1g,562
|
|
43
|
+
service_forge/workflow/workflow.py,sha256=G8p9MW96LHfEZKHbx9p2Pv82WiisKahx9XiB5FKkRGA,10479
|
|
44
|
+
service_forge/workflow/workflow_factory.py,sha256=OsfOwsE-TxWmVNCNhdmwTEgnSLosFe8Q7j8L9QX8xBM,9580
|
|
45
|
+
service_forge/workflow/workflow_group.py,sha256=7KyqMRblpt40zKWBmYq4IUmcFRKRywcB1tSwRz0oirE,850
|
|
46
|
+
service_forge/workflow/workflow_type.py,sha256=zRc-gL2LBE-gOgTUCU5-VDWeGUzuQahkHIg98ipEvQg,1629
|
|
47
|
+
service_forge/workflow/nodes/__init__.py,sha256=o0Ks5F8vP5CTd4rBDLHoYjohkzFh8-fSLM69qVGGBGM,337
|
|
48
|
+
service_forge/workflow/nodes/control/if_node.py,sha256=c58beptuUgxWBDHjYylrc1cph9GLMI9WN1Qv9cQB5Nw,703
|
|
49
|
+
service_forge/workflow/nodes/input/console_input_node.py,sha256=GhQjWRgYy3aRfYUfaEql-_Xi10cca75oz-vmSZkR54w,683
|
|
50
|
+
service_forge/workflow/nodes/llm/query_llm_node.py,sha256=uwcWO6Q-qAG16yJqEGLJau8YxcJBGsBJoGVUBQTBWZk,1155
|
|
51
|
+
service_forge/workflow/nodes/nested/workflow_node.py,sha256=h5NXhRCUGaoNmqMV2PXR6JNwTCM8MCRVA6ocOjoDzhs,747
|
|
52
|
+
service_forge/workflow/nodes/output/kafka_output_node.py,sha256=mC6qRMGsuwU6qXAfXA-0ZFZudrlwmgRYOJRULUrtH40,682
|
|
53
|
+
service_forge/workflow/nodes/output/print_node.py,sha256=OSgeRQOd3dq88a1plx30g9-VB793RbXnIa5X8MF9fCo,656
|
|
54
|
+
service_forge/workflow/nodes/test/if_console_input_node.py,sha256=CtKHkFqr8PN974_iGP2VSBmNpXZ-KumRHCpoRR5RyF8,956
|
|
55
|
+
service_forge/workflow/nodes/test/time_consuming_node.py,sha256=uFThKZkWOIWKcGqQuzxftZS7IlWFBbQk0YNgViXFlSg,1759
|
|
56
|
+
service_forge/workflow/triggers/__init__.py,sha256=-wfqu6qK-8N8LNw3AgyXAR-nBk_RbckfM1fWRJ9YW3Q,171
|
|
57
|
+
service_forge/workflow/triggers/fast_api_trigger.py,sha256=Aw22r6tHHi5SZLxN4xG_YtVVDeRSdwdtH16-mKx_waI,4234
|
|
58
|
+
service_forge/workflow/triggers/kafka_api_trigger.py,sha256=jGnb4dkvh01Jy3CIOvgcQQ3RjsCZCGyXp2NxzCUrd6Y,1498
|
|
59
|
+
service_forge/workflow/triggers/once_trigger.py,sha256=X0MidqEDNATzYEQY_MwpwKEqgzBFn1lc9q8ci14Mpt8,508
|
|
60
|
+
service_forge/workflow/triggers/period_trigger.py,sha256=WE55k5ZpCmu666MPPQC5XSP_L_OzGlwt7v8mAnw4Qas,703
|
|
61
|
+
service_forge-0.1.0.dist-info/METADATA,sha256=SBORW-NCgm28-2P_kwdauOf9DP9LYXzXDsVgkrVRssU,2166
|
|
62
|
+
service_forge-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
63
|
+
service_forge-0.1.0.dist-info/entry_points.txt,sha256=WHntHW7GAyKQUEeMcMvHDZ7_xAb0-cZeAK4iJeu9lm8,51
|
|
64
|
+
service_forge-0.1.0.dist-info/RECORD,,
|