mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-09-08 12:30:14 +00:00
feat(web): copy awel flow (#1200)
Co-authored-by: Fangyin Cheng <staneyffer@gmail.com>
This commit is contained in:
@@ -649,8 +649,8 @@ class BaseMetadata(BaseResource):
|
||||
# TODO, skip the optional parameters.
|
||||
raise FlowParameterMetadataException(
|
||||
f"Parameters count not match(current key: {self.id}). "
|
||||
f"Expected {len(self.parameters)}, "
|
||||
f"but got {len(view_parameters)} from JSON metadata."
|
||||
f"Expected {len(current_required_parameters)}, "
|
||||
f"but got {len(view_required_parameters)} from JSON metadata."
|
||||
f"Required parameters: {current_required_parameters.keys()}, "
|
||||
f"but got {view_required_parameters.keys()}."
|
||||
)
|
||||
|
@@ -26,6 +26,9 @@ from .exceptions import (
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
AWEL_FLOW_VERSION = "0.1.1"
|
||||
|
||||
|
||||
class FlowPositionData(BaseModel):
|
||||
"""Position of a node in a flow."""
|
||||
|
||||
@@ -152,12 +155,10 @@ class State(str, Enum):
|
||||
INITIALIZING = "initializing"
|
||||
DEVELOPING = "developing"
|
||||
TESTING = "testing"
|
||||
READY_TO_DEPLOY = "ready_to_deploy"
|
||||
DEPLOYED = "deployed"
|
||||
RUNNING = "running"
|
||||
PAUSED = "paused"
|
||||
DISABLED = "disabled"
|
||||
ENABLED = "enabled"
|
||||
LOAD_FAILED = "load_failed"
|
||||
|
||||
@classmethod
|
||||
def value_of(cls, value: Optional[str]) -> "State":
|
||||
@@ -169,6 +170,60 @@ class State(str, Enum):
|
||||
return state
|
||||
raise ValueError(f"Invalid state value: {value}")
|
||||
|
||||
@classmethod
|
||||
def can_change_state(cls, current_state: "State", new_state: "State") -> bool:
|
||||
"""Change the state of the flow panel."""
|
||||
allowed_transitions: Dict[State, List[State]] = {
|
||||
State.INITIALIZING: [
|
||||
State.DEVELOPING,
|
||||
State.INITIALIZING,
|
||||
State.LOAD_FAILED,
|
||||
],
|
||||
State.DEVELOPING: [
|
||||
State.TESTING,
|
||||
State.DEPLOYED,
|
||||
State.DISABLED,
|
||||
State.DEVELOPING,
|
||||
State.LOAD_FAILED,
|
||||
],
|
||||
State.TESTING: [
|
||||
State.TESTING,
|
||||
State.DEPLOYED,
|
||||
State.DEVELOPING,
|
||||
State.DISABLED,
|
||||
State.RUNNING,
|
||||
State.LOAD_FAILED,
|
||||
],
|
||||
State.DEPLOYED: [
|
||||
State.DEPLOYED,
|
||||
State.DEVELOPING,
|
||||
State.TESTING,
|
||||
State.DISABLED,
|
||||
State.RUNNING,
|
||||
State.LOAD_FAILED,
|
||||
],
|
||||
State.RUNNING: [
|
||||
State.RUNNING,
|
||||
State.DEPLOYED,
|
||||
State.TESTING,
|
||||
State.DISABLED,
|
||||
],
|
||||
State.DISABLED: [State.DISABLED, State.DEPLOYED],
|
||||
State.LOAD_FAILED: [
|
||||
State.LOAD_FAILED,
|
||||
State.DEVELOPING,
|
||||
State.DEPLOYED,
|
||||
State.DISABLED,
|
||||
],
|
||||
}
|
||||
if new_state in allowed_transitions[current_state]:
|
||||
return True
|
||||
else:
|
||||
logger.error(
|
||||
f"Invalid state transition from {current_state} to {new_state}"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
class FlowCategory(str, Enum):
|
||||
"""Flow category."""
|
||||
@@ -219,6 +274,11 @@ class FlowPanel(BaseModel):
|
||||
state: State = Field(
|
||||
default=State.INITIALIZING, description="Current state of the flow panel"
|
||||
)
|
||||
error_message: Optional[str] = Field(
|
||||
None,
|
||||
description="Error message of load the flow panel",
|
||||
examples=["Unable to load the flow panel."],
|
||||
)
|
||||
source: Optional[str] = Field(
|
||||
"DBGPT-WEB",
|
||||
description="Source of the flow panel",
|
||||
@@ -229,7 +289,9 @@ class FlowPanel(BaseModel):
|
||||
description="Source url of the flow panel",
|
||||
)
|
||||
version: Optional[str] = Field(
|
||||
"0.1.0", description="Version of the flow panel", examples=["0.1.0", "0.2.0"]
|
||||
AWEL_FLOW_VERSION,
|
||||
description="Version of the flow panel",
|
||||
examples=["0.1.0", "0.2.0"],
|
||||
)
|
||||
editable: bool = Field(
|
||||
True,
|
||||
@@ -251,26 +313,6 @@ class FlowPanel(BaseModel):
|
||||
examples=["2021-08-01 12:00:00", "2021-08-01 12:00:01", "2021-08-01 12:00:02"],
|
||||
)
|
||||
|
||||
def change_state(self, new_state: State) -> bool:
|
||||
"""Change the state of the flow panel."""
|
||||
allowed_transitions: Dict[State, List[State]] = {
|
||||
State.INITIALIZING: [State.DEVELOPING],
|
||||
State.DEVELOPING: [State.TESTING, State.DISABLED],
|
||||
State.TESTING: [State.READY_TO_DEPLOY, State.DEVELOPING, State.DISABLED],
|
||||
State.READY_TO_DEPLOY: [State.DEPLOYED, State.DEVELOPING],
|
||||
State.DEPLOYED: [State.RUNNING, State.DISABLED],
|
||||
State.RUNNING: [State.PAUSED, State.DISABLED, State.DEPLOYED],
|
||||
State.PAUSED: [State.RUNNING, State.DISABLED],
|
||||
State.DISABLED: [State.ENABLED],
|
||||
State.ENABLED: [s for s in State if s != State.INITIALIZING],
|
||||
}
|
||||
if new_state in allowed_transitions[self.state]:
|
||||
self.state = new_state
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Invalid state transition from {self.state} to {new_state}")
|
||||
return False
|
||||
|
||||
@root_validator(pre=True)
|
||||
def pre_fill(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Pre fill the metadata."""
|
||||
|
@@ -4,10 +4,12 @@ After DB-GPT started, the trigger manager will be initialized and register all t
|
||||
"""
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, Dict, Optional
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union
|
||||
|
||||
from dbgpt.component import BaseComponent, ComponentType, SystemApp
|
||||
|
||||
from ..util.http_util import join_paths
|
||||
from .base import Trigger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -64,6 +66,7 @@ class HttpTriggerManager(TriggerManager):
|
||||
self._router_prefix = router_prefix
|
||||
self._router = router
|
||||
self._trigger_map: Dict[str, Trigger] = {}
|
||||
self._router_tables: Dict[str, Set[str]] = defaultdict(set)
|
||||
|
||||
def register_trigger(self, trigger: Any, system_app: SystemApp) -> None:
|
||||
"""Register a trigger to current manager."""
|
||||
@@ -73,15 +76,23 @@ class HttpTriggerManager(TriggerManager):
|
||||
raise ValueError(f"Current trigger {trigger} not an object of HttpTrigger")
|
||||
trigger_id = trigger.node_id
|
||||
if trigger_id not in self._trigger_map:
|
||||
if trigger.register_to_app():
|
||||
app = system_app.app
|
||||
if not app:
|
||||
raise ValueError("System app not initialized")
|
||||
# Mount to app, support dynamic route.
|
||||
trigger.mount_to_app(app, self._router_prefix)
|
||||
else:
|
||||
trigger.mount_to_router(self._router)
|
||||
self._trigger_map[trigger_id] = trigger
|
||||
path = join_paths(self._router_prefix, trigger._endpoint)
|
||||
methods = trigger._methods
|
||||
# Check whether the route is already registered
|
||||
self._register_route_tables(path, methods)
|
||||
try:
|
||||
if trigger.register_to_app():
|
||||
app = system_app.app
|
||||
if not app:
|
||||
raise ValueError("System app not initialized")
|
||||
# Mount to app, support dynamic route.
|
||||
trigger.mount_to_app(app, self._router_prefix)
|
||||
else:
|
||||
trigger.mount_to_router(self._router)
|
||||
self._trigger_map[trigger_id] = trigger
|
||||
except Exception as e:
|
||||
self._unregister_route_tables(path, methods)
|
||||
raise e
|
||||
|
||||
def unregister_trigger(self, trigger: Any, system_app: SystemApp) -> None:
|
||||
"""Unregister a trigger to current manager."""
|
||||
@@ -96,6 +107,9 @@ class HttpTriggerManager(TriggerManager):
|
||||
if not app:
|
||||
raise ValueError("System app not initialized")
|
||||
trigger.remove_from_app(app, self._router_prefix)
|
||||
self._unregister_route_tables(
|
||||
join_paths(self._router_prefix, trigger._endpoint), trigger._methods
|
||||
)
|
||||
del self._trigger_map[trigger_id]
|
||||
|
||||
def _init_app(self, system_app: SystemApp):
|
||||
@@ -120,6 +134,34 @@ class HttpTriggerManager(TriggerManager):
|
||||
"""
|
||||
return len(self._trigger_map) > 0
|
||||
|
||||
def _register_route_tables(
|
||||
self, path: str, methods: Optional[Union[str, List[str]]]
|
||||
):
|
||||
methods = self._parse_methods(methods)
|
||||
tables = self._router_tables[path]
|
||||
for m in methods:
|
||||
if m in tables:
|
||||
raise ValueError(f"Route {path} method {m} already registered")
|
||||
tables.add(m)
|
||||
self._router_tables[path] = tables
|
||||
|
||||
def _unregister_route_tables(
|
||||
self, path: str, methods: Optional[Union[str, List[str]]]
|
||||
):
|
||||
methods = self._parse_methods(methods)
|
||||
tables = self._router_tables[path]
|
||||
for m in methods:
|
||||
if m in tables:
|
||||
tables.remove(m)
|
||||
self._router_tables[path] = tables
|
||||
|
||||
def _parse_methods(self, methods: Optional[Union[str, List[str]]]) -> List[str]:
|
||||
if not methods:
|
||||
return ["GET"]
|
||||
elif isinstance(methods, str):
|
||||
return [methods]
|
||||
return [m.upper() for m in methods]
|
||||
|
||||
|
||||
class DefaultTriggerManager(TriggerManager, BaseComponent):
|
||||
"""Default trigger manager for AWEL.
|
||||
|
Reference in New Issue
Block a user