model-compose 0.0.12__tar.gz → 0.0.13__tar.gz
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.
- {model_compose-0.0.12/src/model_compose.egg-info → model_compose-0.0.13}/PKG-INFO +2 -1
- {model_compose-0.0.12 → model_compose-0.0.13}/pyproject.toml +11 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/component.py +3 -3
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/base.py +4 -3
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/http_client.py +4 -6
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/http_server.py +2 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/compose/manager.py +2 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/controller.py +2 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/engine/base.py +31 -7
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/engine/http_server.py +11 -3
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/engine/mcp_server.py +11 -3
- model_compose-0.0.13/src/mindor/core/controller/runner/__init__.py +1 -0
- model_compose-0.0.13/src/mindor/core/controller/runner/client.py +11 -0
- model_compose-0.0.13/src/mindor/core/controller/runner/http_client.py +26 -0
- model_compose-0.0.13/src/mindor/core/controller/runner/mcp_client.py +10 -0
- model_compose-0.0.13/src/mindor/core/controller/runner/runner.py +33 -0
- model_compose-0.0.13/src/mindor/core/controller/webui/__init__.py +1 -0
- model_compose-0.0.13/src/mindor/core/controller/webui/gradio.py +88 -0
- model_compose-0.0.13/src/mindor/core/controller/webui/schema.py +94 -0
- model_compose-0.0.13/src/mindor/core/controller/webui/webui.py +74 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/listener/engine/base.py +2 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/listener/engine/http_callback.py +2 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/listener/listener.py +2 -2
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/template.py +5 -5
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/workflow/job.py +4 -4
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/workflow/workflow.py +5 -12
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/impl/http_client.py +0 -7
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/common.py +2 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/http_client.py +7 -6
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/impl/common.py +2 -0
- model_compose-0.0.13/src/mindor/dsl/schema/controller/impl/webui.py +7 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/workflow.py +10 -1
- {model_compose-0.0.12 → model_compose-0.0.13/src/model_compose.egg-info}/PKG-INFO +2 -1
- {model_compose-0.0.12 → model_compose-0.0.13}/src/model_compose.egg-info/SOURCES.txt +10 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/model_compose.egg-info/requires.txt +1 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/LICENSE +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/README.md +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/setup.cfg +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/cli/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/cli/compose.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/context.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/compose/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/compose/compose.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/engine/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/gateway/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/gateway/engine/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/gateway/engine/base.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/gateway/engine/http_tunnel.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/gateway/gateway.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/listener/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/listener/engine/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/runtime/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/runtime/env.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/services/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/services/async_service.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/expiring.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/http_client.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/http_headers.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/resources.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/time.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/utils/workqueue.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/workflow/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/workflow/context.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/loader.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/action.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/impl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/impl/common.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/impl/http_server.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/impl/mcp_client.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/action/impl/mcp_server.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/component.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/http_server.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/mcp_client.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/mcp_server.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/component/impl/types.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/compose.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/controller.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/impl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/impl/http_server.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/impl/mcp_server.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/controller/impl/types.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/gateway/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/gateway/gateway.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/gateway/impl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/gateway/impl/common.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/gateway/impl/http_tunnel.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/gateway/impl/types.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/listener/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/listener/impl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/listener/impl/common.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/listener/impl/http_callback.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/listener/impl/types.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/listener/listener.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/runtime/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/runtime/impl/__init__.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/runtime/impl/common.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/runtime/impl/docker.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/runtime/impl/types.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/dsl/schema/runtime/runtime.py +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/model_compose.egg-info/dependency_links.txt +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/model_compose.egg-info/entry_points.txt +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/src/model_compose.egg-info/top_level.txt +0 -0
- {model_compose-0.0.12 → model_compose-0.0.13}/tests/test_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: model-compose
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.13
|
|
4
4
|
Summary: model-compose: Declarative AI Model and Workflow Orchestrator (from Mindor)
|
|
5
5
|
Author-email: Hanyeol Cho <hanyeol.cho@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,6 +16,7 @@ Requires-Dist: requests
|
|
|
16
16
|
Requires-Dist: fastapi
|
|
17
17
|
Requires-Dist: uvicorn
|
|
18
18
|
Requires-Dist: ulid
|
|
19
|
+
Requires-Dist: gradio
|
|
19
20
|
Dynamic: license-file
|
|
20
21
|
|
|
21
22
|
# model-compose: Declarative AI Model and Workflow Orchestrator (from Mindor)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "model-compose"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.13"
|
|
4
4
|
description = "model-compose: Declarative AI Model and Workflow Orchestrator (from Mindor)"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Hanyeol Cho", email = "hanyeol.cho@gmail.com" }
|
|
@@ -8,7 +8,16 @@ authors = [
|
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = "MIT"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"click",
|
|
11
|
+
"click",
|
|
12
|
+
"pyyaml",
|
|
13
|
+
"pydantic",
|
|
14
|
+
"python-dotenv",
|
|
15
|
+
"aiohttp",
|
|
16
|
+
"requests",
|
|
17
|
+
"fastapi",
|
|
18
|
+
"uvicorn",
|
|
19
|
+
"ulid",
|
|
20
|
+
"gradio"
|
|
12
21
|
]
|
|
13
22
|
|
|
14
23
|
[project.scripts]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
2
|
from mindor.dsl.schema.component import ComponentConfig
|
|
3
|
-
from .engine import
|
|
3
|
+
from .engine import ComponentEngine, ComponentEngineMap
|
|
4
4
|
|
|
5
|
-
ComponentInstances: Dict[str,
|
|
5
|
+
ComponentInstances: Dict[str, ComponentEngine] = {}
|
|
6
6
|
|
|
7
7
|
class ComponentResolver:
|
|
8
8
|
def __init__(self, components: Dict[str, ComponentConfig]):
|
|
@@ -27,7 +27,7 @@ class ComponentResolver:
|
|
|
27
27
|
|
|
28
28
|
return default_ids[0] if default_ids else "__default__"
|
|
29
29
|
|
|
30
|
-
def create_component(id: str, config: ComponentConfig, env: Dict[str, str], daemon: bool) ->
|
|
30
|
+
def create_component(id: str, config: ComponentConfig, env: Dict[str, str], daemon: bool) -> ComponentEngine:
|
|
31
31
|
try:
|
|
32
32
|
component = ComponentInstances[id] if id in ComponentInstances else None
|
|
33
33
|
|
|
@@ -30,14 +30,15 @@ class ActionResolver:
|
|
|
30
30
|
|
|
31
31
|
return default_ids[0] if default_ids else "__default__"
|
|
32
32
|
|
|
33
|
-
class
|
|
33
|
+
class ComponentEngine(AsyncService):
|
|
34
34
|
def __init__(self, id: str, config: ComponentConfig, env: Dict[str, str], daemon: bool):
|
|
35
35
|
super().__init__(daemon)
|
|
36
36
|
|
|
37
37
|
self.id: str = id
|
|
38
38
|
self.config: ComponentConfig = config
|
|
39
39
|
self.env: Dict[str, str] = env
|
|
40
|
-
|
|
40
|
+
self.queue: Optional[WorkQueue] = None
|
|
41
|
+
|
|
41
42
|
if self.config.max_concurrent_count > 0:
|
|
42
43
|
self.queue = WorkQueue(self.config.max_concurrent_count, self._run)
|
|
43
44
|
|
|
@@ -66,4 +67,4 @@ class BaseComponent(AsyncService):
|
|
|
66
67
|
async def _run(self, action: ActionConfig, context: ComponentContext) -> Any:
|
|
67
68
|
pass
|
|
68
69
|
|
|
69
|
-
ComponentEngineMap: Dict[ComponentType, Type[
|
|
70
|
+
ComponentEngineMap: Dict[ComponentType, Type[ComponentEngine]] = {}
|
{model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/http_client.py
RENAMED
|
@@ -4,7 +4,7 @@ from mindor.dsl.schema.action import ActionConfig, HttpClientActionConfig, HttpC
|
|
|
4
4
|
from mindor.core.listener import HttpCallbackListener
|
|
5
5
|
from mindor.core.utils.http_client import HttpClient
|
|
6
6
|
from mindor.core.utils.time import parse_duration
|
|
7
|
-
from .base import
|
|
7
|
+
from .base import ComponentEngine, ComponentType, ComponentEngineMap
|
|
8
8
|
from .context import ComponentContext
|
|
9
9
|
from datetime import datetime, timezone
|
|
10
10
|
import asyncio
|
|
@@ -79,7 +79,7 @@ class HttpClientAction:
|
|
|
79
79
|
body = context.render_template(self.config.body)
|
|
80
80
|
headers = context.render_template(self.config.headers)
|
|
81
81
|
|
|
82
|
-
response = await self.client.request(url, method, params, body, headers)
|
|
82
|
+
response, result = await self.client.request(url, method, params, body, headers), None
|
|
83
83
|
|
|
84
84
|
if response:
|
|
85
85
|
context.register_source("response", response)
|
|
@@ -90,9 +90,7 @@ class HttpClientAction:
|
|
|
90
90
|
if result:
|
|
91
91
|
context.register_source("result", result)
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return context.render_template(self.config.output) if self.config.output else response
|
|
93
|
+
return context.render_template(self.config.output) if self.config.output else (result or response)
|
|
96
94
|
|
|
97
95
|
def _resolve_request_url(self, context: ComponentContext) -> str:
|
|
98
96
|
if self.base_url and self.config.path:
|
|
@@ -109,7 +107,7 @@ class HttpClientAction:
|
|
|
109
107
|
|
|
110
108
|
return None
|
|
111
109
|
|
|
112
|
-
class HttpClientComponent(
|
|
110
|
+
class HttpClientComponent(ComponentEngine):
|
|
113
111
|
def __init__(self, id: str, config: HttpClientComponentConfig, env: Dict[str, str], daemon: bool):
|
|
114
112
|
super().__init__(id, config, env, daemon)
|
|
115
113
|
|
{model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/component/engine/http_server.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
2
|
from mindor.dsl.schema.component import HttpServerComponentConfig
|
|
3
|
-
from .base import
|
|
3
|
+
from .base import ComponentEngine, ComponentType, ComponentEngineMap, ActionConfig
|
|
4
4
|
from .context import ComponentContext
|
|
5
5
|
|
|
6
|
-
class HttpServerComponent(
|
|
6
|
+
class HttpServerComponent(ComponentEngine):
|
|
7
7
|
def __init__(self, id: str, config: HttpServerComponentConfig, env: Dict[str, str], daemon: bool):
|
|
8
8
|
super().__init__(id, config, env, daemon)
|
|
9
9
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
2
|
from mindor.dsl.schema.compose import ComposeConfig
|
|
3
|
-
from mindor.core.controller import
|
|
3
|
+
from mindor.core.controller import ControllerEngine, TaskState, create_controller
|
|
4
4
|
|
|
5
5
|
class ComposeManager:
|
|
6
6
|
def __init__(self, config: ComposeConfig, env: Dict[str, str], daemon: bool = True):
|
|
7
7
|
self.config: ComposeConfig = config
|
|
8
|
-
self.controller:
|
|
8
|
+
self.controller: ControllerEngine = create_controller(self.config.controller, self.config.components, self.config.listeners, self.config.workflows, env, daemon)
|
|
9
9
|
|
|
10
10
|
async def launch_services(self, detach: bool, background: bool = False):
|
|
11
11
|
await self.controller.start(background=background)
|
|
@@ -3,9 +3,9 @@ from mindor.dsl.schema.controller import ControllerConfig
|
|
|
3
3
|
from mindor.dsl.schema.component import ComponentConfig
|
|
4
4
|
from mindor.dsl.schema.listener import ListenerConfig
|
|
5
5
|
from mindor.dsl.schema.workflow import WorkflowConfig
|
|
6
|
-
from .engine import
|
|
6
|
+
from .engine import ControllerEngine, ControllerEngineMap
|
|
7
7
|
|
|
8
|
-
def create_controller(config: ControllerConfig, components: Dict[str, ComponentConfig], listeners: List[ListenerConfig], workflows: Dict[str, WorkflowConfig], env: Dict[str, str], daemon: bool) ->
|
|
8
|
+
def create_controller(config: ControllerConfig, components: Dict[str, ComponentConfig], listeners: List[ListenerConfig], workflows: Dict[str, WorkflowConfig], env: Dict[str, str], daemon: bool) -> ControllerEngine:
|
|
9
9
|
try:
|
|
10
10
|
return ControllerEngineMap[config.type](config, components, listeners, workflows, env, daemon)
|
|
11
11
|
except KeyError:
|
|
@@ -6,9 +6,10 @@ from mindor.dsl.schema.component import ComponentConfig
|
|
|
6
6
|
from mindor.dsl.schema.listener import ListenerConfig
|
|
7
7
|
from mindor.dsl.schema.workflow import WorkflowConfig
|
|
8
8
|
from mindor.core.services import AsyncService
|
|
9
|
-
from mindor.core.component import
|
|
10
|
-
from mindor.core.listener import
|
|
9
|
+
from mindor.core.component import ComponentEngine, create_component
|
|
10
|
+
from mindor.core.listener import ListenerEngine, create_listener
|
|
11
11
|
from mindor.core.workflow import Workflow, WorkflowResolver, create_workflow
|
|
12
|
+
from mindor.core.controller.webui import ControllerWebUI
|
|
12
13
|
from mindor.core.utils.workqueue import WorkQueue
|
|
13
14
|
from mindor.core.utils.expiring import ExpiringDict
|
|
14
15
|
|
|
@@ -22,8 +23,16 @@ class TaskState:
|
|
|
22
23
|
output: Optional[Any] = None
|
|
23
24
|
error: Optional[Any] = None
|
|
24
25
|
|
|
25
|
-
class
|
|
26
|
-
def __init__(
|
|
26
|
+
class ControllerEngine(AsyncService):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
config: ControllerConfig,
|
|
30
|
+
components: Dict[str, ComponentConfig],
|
|
31
|
+
listeners: List[ListenerConfig],
|
|
32
|
+
workflows: Dict[str, WorkflowConfig],
|
|
33
|
+
env: Dict[str, str],
|
|
34
|
+
daemon: bool
|
|
35
|
+
):
|
|
27
36
|
super().__init__(daemon)
|
|
28
37
|
|
|
29
38
|
self.config: ControllerConfig = config
|
|
@@ -66,6 +75,9 @@ class BaseController(AsyncService):
|
|
|
66
75
|
await self._start_components()
|
|
67
76
|
await self._start_listeners()
|
|
68
77
|
|
|
78
|
+
if self.config.webui:
|
|
79
|
+
await self._start_webui()
|
|
80
|
+
|
|
69
81
|
await super()._start()
|
|
70
82
|
|
|
71
83
|
async def _stop(self) -> None:
|
|
@@ -76,6 +88,9 @@ class BaseController(AsyncService):
|
|
|
76
88
|
await self._stop_listeners()
|
|
77
89
|
await self._stop_components()
|
|
78
90
|
|
|
91
|
+
if self.config.webui:
|
|
92
|
+
await self._stop_webui()
|
|
93
|
+
|
|
79
94
|
await super()._stop()
|
|
80
95
|
|
|
81
96
|
async def _start_components(self) -> None:
|
|
@@ -90,6 +105,12 @@ class BaseController(AsyncService):
|
|
|
90
105
|
async def _stop_listeners(self) -> None:
|
|
91
106
|
await asyncio.gather(*[ listener.stop() for listener in self._create_listeners() ])
|
|
92
107
|
|
|
108
|
+
async def _start_webui(self) -> None:
|
|
109
|
+
await asyncio.gather(*[ self._create_webui().start() ])
|
|
110
|
+
|
|
111
|
+
async def _stop_webui(self) -> None:
|
|
112
|
+
await asyncio.gather(*[ self._create_webui().stop() ])
|
|
113
|
+
|
|
93
114
|
async def _run_workflow(self, task_id: str, workflow_id: Optional[str], input: Dict[str, Any]) -> TaskState:
|
|
94
115
|
state = TaskState(task_id=task_id, status="processing")
|
|
95
116
|
with self.task_states_lock:
|
|
@@ -107,13 +128,16 @@ class BaseController(AsyncService):
|
|
|
107
128
|
|
|
108
129
|
return state
|
|
109
130
|
|
|
110
|
-
def _create_components(self) -> List[
|
|
131
|
+
def _create_components(self) -> List[ComponentEngine]:
|
|
111
132
|
return [ create_component(component_id, config, self.env, self.daemon) for component_id, config in self.components.items() ]
|
|
112
133
|
|
|
113
|
-
def _create_listeners(self) -> List[
|
|
134
|
+
def _create_listeners(self) -> List[ListenerEngine]:
|
|
114
135
|
return [ create_listener(config, self.env, self.daemon) for config in self.listeners ]
|
|
115
136
|
|
|
137
|
+
def _create_webui(self) -> ControllerWebUI:
|
|
138
|
+
return ControllerWebUI(self.config.webui, self.config, self.components, self.workflows, self.env, self.daemon)
|
|
139
|
+
|
|
116
140
|
def _create_workflow(self, workflow_id: Optional[str]) -> Workflow:
|
|
117
141
|
return create_workflow(*WorkflowResolver(self.workflows).resolve(workflow_id), self.components, self.env)
|
|
118
142
|
|
|
119
|
-
ControllerEngineMap: Dict[ControllerType, Type[
|
|
143
|
+
ControllerEngineMap: Dict[ControllerType, Type[ControllerEngine]] = {}
|
{model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/engine/http_server.py
RENAMED
|
@@ -7,7 +7,7 @@ from mindor.dsl.schema.listener import ListenerConfig
|
|
|
7
7
|
from mindor.dsl.schema.component import ComponentConfig
|
|
8
8
|
from mindor.dsl.schema.workflow import WorkflowConfig
|
|
9
9
|
from mindor.core.utils.resources import StreamResource
|
|
10
|
-
from .base import
|
|
10
|
+
from .base import ControllerEngine, ControllerType, ControllerEngineMap, TaskState
|
|
11
11
|
|
|
12
12
|
from fastapi import FastAPI, APIRouter, Body, HTTPException
|
|
13
13
|
from fastapi.responses import Response, JSONResponse, StreamingResponse
|
|
@@ -35,8 +35,16 @@ class TaskResult(BaseModel):
|
|
|
35
35
|
error=instance.error
|
|
36
36
|
)
|
|
37
37
|
|
|
38
|
-
class HttpServerController(
|
|
39
|
-
def __init__(
|
|
38
|
+
class HttpServerController(ControllerEngine):
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
config: HttpServerControllerConfig,
|
|
42
|
+
components: Dict[str, ComponentConfig],
|
|
43
|
+
listeners: List[ListenerConfig],
|
|
44
|
+
workflows: Dict[str, WorkflowConfig],
|
|
45
|
+
env: Dict[str, str],
|
|
46
|
+
daemon: bool
|
|
47
|
+
):
|
|
40
48
|
super().__init__(config, components, listeners, workflows, env, daemon)
|
|
41
49
|
|
|
42
50
|
self.server: Optional[uvicorn.Server] = None
|
{model_compose-0.0.12 → model_compose-0.0.13}/src/mindor/core/controller/engine/mcp_server.py
RENAMED
|
@@ -3,10 +3,18 @@ from mindor.dsl.schema.controller import McpServerControllerConfig
|
|
|
3
3
|
from mindor.dsl.schema.listener import ListenerConfig
|
|
4
4
|
from mindor.dsl.schema.component import ComponentConfig
|
|
5
5
|
from mindor.dsl.schema.workflow import WorkflowConfig
|
|
6
|
-
from .base import
|
|
6
|
+
from .base import ControllerEngine, ControllerType, ControllerEngineMap
|
|
7
7
|
|
|
8
|
-
class McpServerController(
|
|
9
|
-
def __init__(
|
|
8
|
+
class McpServerController(ControllerEngine):
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
config: McpServerControllerConfig,
|
|
12
|
+
components: Dict[str, ComponentConfig],
|
|
13
|
+
listeners: List[ListenerConfig],
|
|
14
|
+
workflows: Dict[str, WorkflowConfig],
|
|
15
|
+
env: Dict[str, str],
|
|
16
|
+
daemon: bool
|
|
17
|
+
):
|
|
10
18
|
super().__init__(config, components, listeners, workflows, env, daemon)
|
|
11
19
|
|
|
12
20
|
async def _serve(self) -> None:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .runner import *
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from mindor.dsl.schema.controller import ControllerConfig
|
|
4
|
+
|
|
5
|
+
class ControllerClient(ABC):
|
|
6
|
+
def __init__(self, config: ControllerConfig):
|
|
7
|
+
self.config: ControllerConfig = config
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
11
|
+
pass
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
|
+
from mindor.dsl.schema.controller import ControllerConfig
|
|
3
|
+
from mindor.core.utils.http_client import HttpClient
|
|
4
|
+
from .runner import ControllerClient
|
|
5
|
+
|
|
6
|
+
class HttpControllerClient(ControllerClient):
|
|
7
|
+
def __init__(self, config: ControllerConfig):
|
|
8
|
+
super().__init__(config)
|
|
9
|
+
|
|
10
|
+
self.client: HttpClient = HttpClient()
|
|
11
|
+
|
|
12
|
+
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
13
|
+
base_path = self.config.base_path if self.config.base_path else ""
|
|
14
|
+
url = f"http://localhost:{self.config.port}{base_path}/workflows"
|
|
15
|
+
method = "POST"
|
|
16
|
+
body = {
|
|
17
|
+
"workflow_id": workflow_id,
|
|
18
|
+
"input": input,
|
|
19
|
+
"wait_for_completion": True,
|
|
20
|
+
"output_only": True
|
|
21
|
+
}
|
|
22
|
+
headers = {
|
|
23
|
+
"Content-Type": "application/json"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return await self.client.request(url, method, None, body, headers)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
|
+
from mindor.dsl.schema.controller import ControllerConfig
|
|
3
|
+
from .runner import ControllerClient
|
|
4
|
+
|
|
5
|
+
class McpControllerClient(ControllerClient):
|
|
6
|
+
def __init__(self, config: ControllerConfig):
|
|
7
|
+
super().__init__(config)
|
|
8
|
+
|
|
9
|
+
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
10
|
+
pass
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from mindor.dsl.schema.controller import ControllerConfig
|
|
4
|
+
from .client import ControllerClient
|
|
5
|
+
from .http_client import HttpControllerClient
|
|
6
|
+
from .mcp_client import McpControllerClient
|
|
7
|
+
|
|
8
|
+
class ControllerClient(ABC):
|
|
9
|
+
def __init__(self, config: ControllerConfig):
|
|
10
|
+
self.config: ControllerConfig = config
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
class ControllerRunner:
|
|
17
|
+
def __init__(self, config: ControllerConfig):
|
|
18
|
+
self.config: ControllerConfig = config
|
|
19
|
+
self.client: ControllerClient = None
|
|
20
|
+
|
|
21
|
+
self._configure_client()
|
|
22
|
+
|
|
23
|
+
def _configure_client(self) -> None:
|
|
24
|
+
if self.config.type == "http-server":
|
|
25
|
+
self.client = HttpControllerClient(self.config)
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
if self.config.type == "mcp-server":
|
|
29
|
+
self.client = McpControllerClient(self.config)
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
33
|
+
return await self.client.run_workflow(workflow_id, input)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .webui import *
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Callable, Awaitable, Any
|
|
2
|
+
from mindor.dsl.schema.workflow import WorkflowVariableConfig
|
|
3
|
+
from .schema import WorkflowSchema
|
|
4
|
+
import gradio, json
|
|
5
|
+
|
|
6
|
+
class GradioWebUIBuilder:
|
|
7
|
+
def build(self, schema: Dict[str, WorkflowSchema], runner: Callable[[Optional[str], Any], Awaitable[Any]]) -> gradio.Blocks:
|
|
8
|
+
with gradio.Blocks() as blocks:
|
|
9
|
+
for workflow_id, workflow in schema.items():
|
|
10
|
+
async def run_workflow(input: Any, workflow_id=workflow_id) -> Any:
|
|
11
|
+
return await runner(workflow_id, input)
|
|
12
|
+
|
|
13
|
+
if len(schema) > 1:
|
|
14
|
+
with gradio.Tab(label=workflow.name or workflow_id):
|
|
15
|
+
self._build_workflow_section(workflow, run_workflow)
|
|
16
|
+
else:
|
|
17
|
+
self._build_workflow_section(workflow, run_workflow)
|
|
18
|
+
|
|
19
|
+
return blocks
|
|
20
|
+
|
|
21
|
+
def _build_workflow_section(self, workflow: WorkflowSchema, runner: Callable[[Any], Awaitable[Any]]) -> gradio.Column:
|
|
22
|
+
with gradio.Column() as section:
|
|
23
|
+
gradio.Markdown(f"## **{workflow.title or 'Untitled Workflow'}**")
|
|
24
|
+
|
|
25
|
+
if workflow.description:
|
|
26
|
+
gradio.Markdown(f"📝 {workflow.description}")
|
|
27
|
+
|
|
28
|
+
gradio.Markdown("#### 📥 Input Parameters")
|
|
29
|
+
input_components = [ self._build_input_component(variable) for variable in workflow.input ]
|
|
30
|
+
run_button = gradio.Button("🚀 Run Workflow", variant="primary")
|
|
31
|
+
|
|
32
|
+
gradio.Markdown("#### 📤 Output Values")
|
|
33
|
+
output_components = [ self._build_output_component(variable) for variable in workflow.output ]
|
|
34
|
+
|
|
35
|
+
if not output_components:
|
|
36
|
+
output_components = gradio.Textbox(label="", lines=8, interactive=False, show_copy_button=True)
|
|
37
|
+
|
|
38
|
+
async def run_workflow(*args):
|
|
39
|
+
input = { variable.name: value for variable, value in zip(workflow.input, args) }
|
|
40
|
+
output = await runner(input)
|
|
41
|
+
|
|
42
|
+
if workflow.output and isinstance(output, dict):
|
|
43
|
+
output = [ output[variable.name] for variable in workflow.output ]
|
|
44
|
+
output = output[0] if len(output) == 1 else output
|
|
45
|
+
|
|
46
|
+
return output
|
|
47
|
+
|
|
48
|
+
run_button.click(
|
|
49
|
+
fn=run_workflow,
|
|
50
|
+
inputs=input_components,
|
|
51
|
+
outputs=output_components
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return section
|
|
55
|
+
|
|
56
|
+
def _build_input_component(self, variable: WorkflowVariableConfig) -> gradio.Component:
|
|
57
|
+
label = f"{variable.name} {'*' if variable.required else ''}"
|
|
58
|
+
info = variable.description or ""
|
|
59
|
+
default = variable.default
|
|
60
|
+
|
|
61
|
+
if variable.type == "string":
|
|
62
|
+
return gradio.Textbox(label=label, value=default or "", info=info)
|
|
63
|
+
|
|
64
|
+
if variable.type == "integer":
|
|
65
|
+
return gradio.Number(label=label, value=default or 0, precision=0, info=info)
|
|
66
|
+
|
|
67
|
+
if variable.type == "float":
|
|
68
|
+
return gradio.Number(label=label, value=default or 0.0, info=info)
|
|
69
|
+
|
|
70
|
+
if variable.type == "boolean":
|
|
71
|
+
return gradio.Checkbox(label=label, value=default or False, info=info)
|
|
72
|
+
|
|
73
|
+
if variable.type == "file":
|
|
74
|
+
return gradio.File(label=label, file_types=["*"], info=info)
|
|
75
|
+
|
|
76
|
+
if variable.type == "select":
|
|
77
|
+
return gradio.Dropdown(choices=variable.options or [], label=label, value=default, info=info)
|
|
78
|
+
|
|
79
|
+
return gradio.Textbox(label=label, value=default or "", info=f"Unsupported type: {variable.type}")
|
|
80
|
+
|
|
81
|
+
def _build_output_component(self, variable: WorkflowVariableConfig) -> gradio.Component:
|
|
82
|
+
label = variable.name
|
|
83
|
+
info = variable.description or ""
|
|
84
|
+
|
|
85
|
+
if variable.type == "string":
|
|
86
|
+
return gradio.Textbox(label=label, interactive=False, show_copy_button=True, info=info)
|
|
87
|
+
|
|
88
|
+
return gradio.Textbox(label=label, info=f"Unsupported type: {variable.type}")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from mindor.dsl.schema.workflow import WorkflowConfig, WorkflowVariableConfig
|
|
4
|
+
from mindor.dsl.schema.component import ComponentConfig
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
class WorkflowVariableResolver:
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.patterns: Dict[str, re.Pattern] = {
|
|
10
|
+
"variable": re.compile(
|
|
11
|
+
r"""\$\{ # ${
|
|
12
|
+
([a-zA-Z_][\w\-]*) # key: input, env, etc.
|
|
13
|
+
(?:\.([^\|\}]+))? # path: key, key.path[0], etc.
|
|
14
|
+
(?:\s*\|\s*([^\}]+))? # default value after `|`
|
|
15
|
+
\}""", # }
|
|
16
|
+
re.VERBOSE,
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
def _enumerate_variables(self, data: Any, wanted_key: str) -> Any:
|
|
21
|
+
if isinstance(data, str):
|
|
22
|
+
variables = []
|
|
23
|
+
|
|
24
|
+
for match in self.patterns["variable"].finditer(data):
|
|
25
|
+
key, path = match.group(1), match.group(2)
|
|
26
|
+
|
|
27
|
+
if key == wanted_key:
|
|
28
|
+
variables.append(path)
|
|
29
|
+
|
|
30
|
+
return variables
|
|
31
|
+
|
|
32
|
+
if isinstance(data, BaseModel):
|
|
33
|
+
return self._enumerate_variables(data.model_dump(exclude_none=True), wanted_key)
|
|
34
|
+
|
|
35
|
+
if isinstance(data, dict):
|
|
36
|
+
return sum([ self._enumerate_variables(v, wanted_key) for v in data.values() ], [])
|
|
37
|
+
|
|
38
|
+
if isinstance(data, list):
|
|
39
|
+
return sum([ self._enumerate_variables(v, wanted_key) for v in data ], [])
|
|
40
|
+
|
|
41
|
+
return []
|
|
42
|
+
|
|
43
|
+
class WorkflowInputResolver(WorkflowVariableResolver):
|
|
44
|
+
def resolve(self, workflow: WorkflowConfig, components: Dict[str, ComponentConfig]) -> List[WorkflowVariableConfig]:
|
|
45
|
+
variables = []
|
|
46
|
+
for job in workflow.jobs.values():
|
|
47
|
+
if not job.input or job.input == "${input}":
|
|
48
|
+
action_id = job.action or "__default__"
|
|
49
|
+
if isinstance(job.component, str):
|
|
50
|
+
component: ComponentConfig = components[job.component] if job.component in components else None
|
|
51
|
+
if component:
|
|
52
|
+
variables.extend(self._enumerate_variables(component.actions[action_id], "input"))
|
|
53
|
+
else:
|
|
54
|
+
variables.extend(self._enumerate_variables(job.component.actions[action_id], "input"))
|
|
55
|
+
else:
|
|
56
|
+
variables.extend(self._enumerate_variables(job.input, "input"))
|
|
57
|
+
|
|
58
|
+
return [ WorkflowVariableConfig(name=name, type="string") for name in set(variables) ]
|
|
59
|
+
|
|
60
|
+
class WorkflowOutputResolver(WorkflowVariableResolver):
|
|
61
|
+
def resolve(self, workflow: WorkflowConfig, components: Dict[str, ComponentConfig]) -> List[WorkflowVariableConfig]:
|
|
62
|
+
variables = []
|
|
63
|
+
for job_id, job in workflow.jobs.items():
|
|
64
|
+
if not self._is_terminal_job(workflow, job_id):
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
if not job.output or job.output == "${output}":
|
|
68
|
+
action_id = job.action or "__default__"
|
|
69
|
+
if isinstance(job.component, str):
|
|
70
|
+
component: ComponentConfig = components[job.component] if job.component in components else None
|
|
71
|
+
if component:
|
|
72
|
+
action = component.actions[action_id]
|
|
73
|
+
if isinstance(action.output, dict):
|
|
74
|
+
variables.extend(action.output.keys())
|
|
75
|
+
else:
|
|
76
|
+
action = component.actions[action_id]
|
|
77
|
+
if isinstance(action.output, dict):
|
|
78
|
+
variables.extend(action.output.keys())
|
|
79
|
+
else:
|
|
80
|
+
if isinstance(job.output, dict):
|
|
81
|
+
variables.extend(job.output.keys())
|
|
82
|
+
|
|
83
|
+
return [ WorkflowVariableConfig(name=name, type="string") for name in set(variables) ]
|
|
84
|
+
|
|
85
|
+
def _is_terminal_job(self, workflow: WorkflowConfig, job_id: str) -> bool:
|
|
86
|
+
return all(job_id not in job.depends_on for other_id, job in workflow.jobs.items() if other_id != job_id)
|
|
87
|
+
|
|
88
|
+
class WorkflowSchema:
|
|
89
|
+
def __init__(self, name: str, title: str, description: Optional[str], input: List[WorkflowVariableConfig], output: List[WorkflowVariableConfig]):
|
|
90
|
+
self.name: str = name
|
|
91
|
+
self.title: str = title
|
|
92
|
+
self.description: Optional[str] = description
|
|
93
|
+
self.input: List[WorkflowVariableConfig] = input
|
|
94
|
+
self.output: List[WorkflowVariableConfig] = output
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
|
|
2
|
+
from mindor.dsl.schema.controller import ControllerWebUIConfig, ControllerConfig
|
|
3
|
+
from mindor.dsl.schema.component import ComponentConfig
|
|
4
|
+
from mindor.dsl.schema.workflow import WorkflowConfig
|
|
5
|
+
from mindor.core.controller.runner import ControllerRunner
|
|
6
|
+
from mindor.core.services import AsyncService
|
|
7
|
+
from .schema import WorkflowSchema, WorkflowInputResolver, WorkflowOutputResolver
|
|
8
|
+
from .gradio import GradioWebUIBuilder
|
|
9
|
+
|
|
10
|
+
from fastapi import FastAPI, APIRouter, Body, HTTPException
|
|
11
|
+
import asyncio, uvicorn
|
|
12
|
+
from gradio import mount_gradio_app
|
|
13
|
+
import gradio, re
|
|
14
|
+
|
|
15
|
+
class ControllerWebUI(AsyncService):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
config: ControllerWebUIConfig,
|
|
19
|
+
controller: ControllerConfig,
|
|
20
|
+
components: Dict[str, ComponentConfig],
|
|
21
|
+
workflows: Dict[str, WorkflowConfig],
|
|
22
|
+
env: Dict[str, str],
|
|
23
|
+
daemon: bool
|
|
24
|
+
):
|
|
25
|
+
super().__init__(daemon)
|
|
26
|
+
|
|
27
|
+
self.config: ControllerWebUIConfig = config
|
|
28
|
+
self.controller: ControllerConfig = controller
|
|
29
|
+
self.components: Dict[str, ComponentConfig] = components
|
|
30
|
+
self.workflows: Dict[str, WorkflowConfig] = workflows
|
|
31
|
+
self.env: Dict[str, str] = env
|
|
32
|
+
self.server: Optional[uvicorn.Server] = None
|
|
33
|
+
self.app: FastAPI = FastAPI()
|
|
34
|
+
self.runner: ControllerRunner = ControllerRunner(controller)
|
|
35
|
+
|
|
36
|
+
self._configure_driver()
|
|
37
|
+
|
|
38
|
+
def _configure_driver(self) -> None:
|
|
39
|
+
if self.config.driver == "gradio":
|
|
40
|
+
blocks: gradio.Blocks = GradioWebUIBuilder().build(
|
|
41
|
+
schema=self._resolve_workflow_schema(),
|
|
42
|
+
runner=self._run_workflow
|
|
43
|
+
)
|
|
44
|
+
self.app = mount_gradio_app(self.app, blocks, path="")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
async def _serve(self) -> None:
|
|
48
|
+
self.server = uvicorn.Server(uvicorn.Config(
|
|
49
|
+
self.app,
|
|
50
|
+
host=self.config.host,
|
|
51
|
+
port=self.config.port,
|
|
52
|
+
log_level="info"
|
|
53
|
+
))
|
|
54
|
+
await self.server.serve()
|
|
55
|
+
|
|
56
|
+
async def _shutdown(self) -> None:
|
|
57
|
+
self.server.should_exit = True
|
|
58
|
+
|
|
59
|
+
async def _run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
60
|
+
return await self.runner.run_workflow(workflow_id, input)
|
|
61
|
+
|
|
62
|
+
def _resolve_workflow_schema(self) -> Dict[str, WorkflowSchema]:
|
|
63
|
+
schema: Dict[str, WorkflowSchema] = {}
|
|
64
|
+
|
|
65
|
+
for workflow_id, workflow in self.workflows.items():
|
|
66
|
+
schema[workflow_id] = WorkflowSchema(
|
|
67
|
+
name=workflow.name,
|
|
68
|
+
title=workflow.title,
|
|
69
|
+
description=workflow.description,
|
|
70
|
+
input=WorkflowInputResolver().resolve(workflow, self.components),
|
|
71
|
+
output=WorkflowOutputResolver().resolve(workflow, self.components)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return schema
|