feat: Add flow2.0 examples

This commit is contained in:
Fangyin Cheng
2024-08-05 18:08:02 +08:00
parent 8563e30092
commit e3e08a83e6
7 changed files with 786 additions and 123 deletions

View File

@@ -19,6 +19,7 @@ from dbgpt.core.awel.util.parameter_util import BaseDynamicOptions, OptionValue
from dbgpt.core.interface.serialization import Serializable from dbgpt.core.interface.serialization import Serializable
from .exceptions import FlowMetadataException, FlowParameterMetadataException from .exceptions import FlowMetadataException, FlowParameterMetadataException
from .ui import UIComponent
_TYPE_REGISTRY: Dict[str, Type] = {} _TYPE_REGISTRY: Dict[str, Type] = {}
@@ -136,6 +137,7 @@ _OPERATOR_CATEGORY_DETAIL = {
"agent": _CategoryDetail("Agent", "The agent operator"), "agent": _CategoryDetail("Agent", "The agent operator"),
"rag": _CategoryDetail("RAG", "The RAG operator"), "rag": _CategoryDetail("RAG", "The RAG operator"),
"experimental": _CategoryDetail("EXPERIMENTAL", "EXPERIMENTAL operator"), "experimental": _CategoryDetail("EXPERIMENTAL", "EXPERIMENTAL operator"),
"example": _CategoryDetail("Example", "Example operator"),
} }
@@ -151,6 +153,7 @@ class OperatorCategory(str, Enum):
AGENT = "agent" AGENT = "agent"
RAG = "rag" RAG = "rag"
EXPERIMENTAL = "experimental" EXPERIMENTAL = "experimental"
EXAMPLE = "example"
def label(self) -> str: def label(self) -> str:
"""Get the label of the category.""" """Get the label of the category."""
@@ -193,6 +196,7 @@ _RESOURCE_CATEGORY_DETAIL = {
"embeddings": _CategoryDetail("Embeddings", "The embeddings resource"), "embeddings": _CategoryDetail("Embeddings", "The embeddings resource"),
"rag": _CategoryDetail("RAG", "The resource"), "rag": _CategoryDetail("RAG", "The resource"),
"vector_store": _CategoryDetail("Vector Store", "The vector store resource"), "vector_store": _CategoryDetail("Vector Store", "The vector store resource"),
"example": _CategoryDetail("Example", "The example resource"),
} }
@@ -209,6 +213,7 @@ class ResourceCategory(str, Enum):
EMBEDDINGS = "embeddings" EMBEDDINGS = "embeddings"
RAG = "rag" RAG = "rag"
VECTOR_STORE = "vector_store" VECTOR_STORE = "vector_store"
EXAMPLE = "example"
def label(self) -> str: def label(self) -> str:
"""Get the label of the category.""" """Get the label of the category."""
@@ -343,6 +348,9 @@ class Parameter(TypeMetadata, Serializable):
alias: Optional[List[str]] = Field( alias: Optional[List[str]] = Field(
None, description="The alias of the parameter(Compatible with old version)" None, description="The alias of the parameter(Compatible with old version)"
) )
ui: Optional[UIComponent] = Field(
None, description="The UI component of the parameter"
)
@model_validator(mode="before") @model_validator(mode="before")
@classmethod @classmethod
@@ -398,6 +406,7 @@ class Parameter(TypeMetadata, Serializable):
label: str, label: str,
name: str, name: str,
type: Type, type: Type,
is_list: bool = False,
optional: bool = False, optional: bool = False,
default: Optional[Union[DefaultParameterType, _MISSING_TYPE]] = _MISSING_VALUE, default: Optional[Union[DefaultParameterType, _MISSING_TYPE]] = _MISSING_VALUE,
placeholder: Optional[DefaultParameterType] = None, placeholder: Optional[DefaultParameterType] = None,
@@ -405,6 +414,7 @@ class Parameter(TypeMetadata, Serializable):
options: Optional[Union[BaseDynamicOptions, List[OptionValue]]] = None, options: Optional[Union[BaseDynamicOptions, List[OptionValue]]] = None,
resource_type: ResourceType = ResourceType.INSTANCE, resource_type: ResourceType = ResourceType.INSTANCE,
alias: Optional[List[str]] = None, alias: Optional[List[str]] = None,
ui: Optional[UIComponent] = None,
): ):
"""Build the parameter from the type.""" """Build the parameter from the type."""
type_name = type.__qualname__ type_name = type.__qualname__
@@ -419,6 +429,7 @@ class Parameter(TypeMetadata, Serializable):
name=name, name=name,
type_name=type_name, type_name=type_name,
type_cls=type_cls, type_cls=type_cls,
is_list=is_list,
category=category.value, category=category.value,
resource_type=resource_type, resource_type=resource_type,
optional=optional, optional=optional,
@@ -427,6 +438,7 @@ class Parameter(TypeMetadata, Serializable):
description=description or label, description=description or label,
options=options, options=options,
alias=alias, alias=alias,
ui=ui,
) )
@classmethod @classmethod
@@ -456,11 +468,12 @@ class Parameter(TypeMetadata, Serializable):
description=data["description"], description=data["description"],
options=data["options"], options=data["options"],
value=data["value"], value=data["value"],
ui=data.get("ui"),
) )
def to_dict(self) -> Dict: def to_dict(self) -> Dict:
"""Convert current metadata to json dict.""" """Convert current metadata to json dict."""
dict_value = model_to_dict(self, exclude={"options", "alias"}) dict_value = model_to_dict(self, exclude={"options", "alias", "ui"})
if not self.options: if not self.options:
dict_value["options"] = None dict_value["options"] = None
elif isinstance(self.options, BaseDynamicOptions): elif isinstance(self.options, BaseDynamicOptions):
@@ -468,6 +481,9 @@ class Parameter(TypeMetadata, Serializable):
dict_value["options"] = [value.to_dict() for value in values] dict_value["options"] = [value.to_dict() for value in values]
else: else:
dict_value["options"] = [value.to_dict() for value in self.options] dict_value["options"] = [value.to_dict() for value in self.options]
if self.ui:
dict_value["ui"] = self.ui.to_dict()
return dict_value return dict_value
def get_dict_options(self) -> Optional[List[Dict]]: def get_dict_options(self) -> Optional[List[Dict]]:

View File

@@ -1,8 +1,9 @@
"""UI components for AWEL flow.""" """UI components for AWEL flow."""
from typing import Any, Dict, List, Literal, Optional from typing import Any, Dict, List, Literal, Optional, Union
from dbgpt._private.pydantic import BaseModel, Field from dbgpt._private.pydantic import BaseModel, Field, model_to_dict
from dbgpt.core.interface.serialization import Serializable
from .exceptions import FlowUIComponentException from .exceptions import FlowUIComponentException
@@ -36,37 +37,6 @@ class RefreshableMixin(BaseModel):
) )
class UIComponent(RefreshableMixin, BaseModel):
"""UI component."""
class UIRange(BaseModel):
"""UI range."""
min: int | float | str | None = Field(None, description="Minimum value")
max: int | float | str | None = Field(None, description="Maximum value")
step: int | float | str | None = Field(None, description="Step value")
format: str | None = Field(None, description="Format")
ui_type: _UI_TYPE = Field(..., description="UI component type")
disabled: bool = Field(
False,
description="Whether the component is disabled",
)
def check_parameter(self, parameter_dict: Dict[str, Any]):
"""Check parameter.
Raises:
FlowUIParameterException: If the parameter is invalid.
"""
def _check_options(self, options: Dict[str, Any]):
"""Check options."""
if not options:
raise FlowUIComponentException("options is required", self.ui_type)
class StatusMixin(BaseModel): class StatusMixin(BaseModel):
"""Status mixin.""" """Status mixin."""
@@ -76,40 +46,6 @@ class StatusMixin(BaseModel):
) )
class RangeMixin(BaseModel):
"""Range mixin."""
ui_range: Optional[UIComponent.UIRange] = Field(
None,
description="Range for the component",
)
class InputMixin(BaseModel):
"""Input mixin."""
class Count(BaseModel):
"""Count."""
show: Optional[bool] = Field(
None,
description="Whether to show count",
)
max: Optional[int] = Field(
None,
description="The maximum count",
)
exceed_strategy: Optional[Literal["cut", "warning"]] = Field(
None,
description="The strategy when the count exceeds",
)
count: Optional[Count] = Field(
None,
description="Count configuration",
)
class PanelEditorMixin(BaseModel): class PanelEditorMixin(BaseModel):
"""Edit the content in the panel.""" """Edit the content in the panel."""
@@ -126,21 +62,64 @@ class PanelEditorMixin(BaseModel):
) )
editor: Optional[Editor] = Field( editor: Optional[Editor] = Field(
None, default_factory=lambda: PanelEditorMixin.Editor(width=800, height=400),
description="The editor configuration", description="The editor configuration",
) )
class UICascader(StatusMixin, UIComponent): class UIComponent(RefreshableMixin, Serializable, BaseModel):
"""UI component."""
class UIAttribute(StatusMixin, BaseModel):
"""Base UI attribute."""
disabled: bool = Field(
False,
description="Whether the component is disabled",
)
ui_type: _UI_TYPE = Field(..., description="UI component type")
attr: Optional[UIAttribute] = Field(
None,
description="The attributes of the component",
)
def check_parameter(self, parameter_dict: Dict[str, Any]):
"""Check parameter.
Raises:
FlowUIParameterException: If the parameter is invalid.
"""
def _check_options(self, options: Dict[str, Any]):
"""Check options."""
if not options:
raise FlowUIComponentException("options is required", self.ui_type)
def to_dict(self) -> Dict:
"""Convert current metadata to json dict."""
return model_to_dict(self)
class UICascader(UIComponent):
"""Cascader component.""" """Cascader component."""
ui_type: Literal["cascader"] = Field("cascader", frozen=True) class UIAttribute(UIComponent.UIAttribute):
"""Cascader attribute."""
show_search: bool = Field( show_search: bool = Field(
False, False,
description="Whether to show search input", description="Whether to show search input",
) )
ui_type: Literal["cascader"] = Field("cascader", frozen=True)
attr: Optional[UIAttribute] = Field(
None,
description="The attributes of the component",
)
def check_parameter(self, parameter_dict: Dict[str, Any]): def check_parameter(self, parameter_dict: Dict[str, Any]):
"""Check parameter.""" """Check parameter."""
options = parameter_dict.get("options") options = parameter_dict.get("options")
@@ -163,10 +142,11 @@ class UICheckbox(UIComponent):
self._check_options(parameter_dict.get("options", {})) self._check_options(parameter_dict.get("options", {}))
class UIDatePicker(StatusMixin, RangeMixin, UIComponent): class UIDatePicker(UIComponent):
"""Date picker component.""" """Date picker component."""
ui_type: Literal["date_picker"] = Field("date_picker", frozen=True) class UIAttribute(UIComponent.UIAttribute):
"""Date picker attribute."""
placement: Optional[ placement: Optional[
Literal["topLeft", "topRight", "bottomLeft", "bottomRight"] Literal["topLeft", "topRight", "bottomLeft", "bottomRight"]
@@ -175,11 +155,19 @@ class UIDatePicker(StatusMixin, RangeMixin, UIComponent):
description="The position of the picker panel, None means bottomLeft", description="The position of the picker panel, None means bottomLeft",
) )
ui_type: Literal["date_picker"] = Field("date_picker", frozen=True)
class UIInput(StatusMixin, InputMixin, UIComponent): attr: Optional[UIAttribute] = Field(
None,
description="The attributes of the component",
)
class UIInput(UIComponent):
"""Input component.""" """Input component."""
ui_type: Literal["input"] = Field("input", frozen=True) class UIAttribute(UIComponent.UIAttribute):
"""Input attribute."""
prefix: Optional[str] = Field( prefix: Optional[str] = Field(
None, None,
@@ -191,17 +179,29 @@ class UIInput(StatusMixin, InputMixin, UIComponent):
description="The suffix, icon or text", description="The suffix, icon or text",
examples=["$", "icon:SearchOutlined"], examples=["$", "icon:SearchOutlined"],
) )
show_count: Optional[bool] = Field(
None,
description="Whether to show count",
)
maxlength: Optional[int] = Field(
None,
description="The maximum length of the input",
)
ui_type: Literal["input"] = Field("input", frozen=True)
attr: Optional[UIAttribute] = Field(
None,
description="The attributes of the component",
)
class UITextArea(PanelEditorMixin, UIInput): class UITextArea(PanelEditorMixin, UIInput):
"""Text area component.""" """Text area component."""
ui_type: Literal["text_area"] = Field("text_area", frozen=True) # type: ignore class AutoSize(BaseModel):
auto_size: Optional[bool] = Field( """Auto size configuration."""
None,
description="Whether the height of the textarea automatically adjusts based "
"on the content",
)
min_rows: Optional[int] = Field( min_rows: Optional[int] = Field(
None, None,
description="The minimum number of rows", description="The minimum number of rows",
@@ -211,6 +211,13 @@ class UITextArea(PanelEditorMixin, UIInput):
description="The maximum number of rows", description="The maximum number of rows",
) )
ui_type: Literal["text_area"] = Field("text_area", frozen=True) # type: ignore
autosize: Optional[Union[bool, AutoSize]] = Field(
None,
description="Whether the height of the textarea automatically adjusts based "
"on the content",
)
class UIAutoComplete(UIInput): class UIAutoComplete(UIInput):
"""Auto complete component.""" """Auto complete component."""
@@ -220,20 +227,42 @@ class UIAutoComplete(UIInput):
) )
class UISlider(RangeMixin, UIComponent): class UISlider(UIComponent):
"""Slider component.""" """Slider component."""
class UIAttribute(UIComponent.UIAttribute):
"""Slider attribute."""
min: Optional[int | float] = Field(
None,
description="The minimum value",
)
max: Optional[int | float] = Field(
None,
description="The maximum value",
)
step: Optional[int | float] = Field(
None,
description="The step of the slider",
)
ui_type: Literal["slider"] = Field("slider", frozen=True) ui_type: Literal["slider"] = Field("slider", frozen=True)
show_input: bool = Field( show_input: bool = Field(
False, description="Whether to display the value in a input component" False, description="Whether to display the value in a input component"
) )
attr: Optional[UIAttribute] = Field(
None,
description="The attributes of the component",
)
class UITimePicker(StatusMixin, UIComponent):
class UITimePicker(UIComponent):
"""Time picker component.""" """Time picker component."""
ui_type: Literal["time_picker"] = Field("time_picker", frozen=True) class UIAttribute(UIComponent.UIAttribute):
"""Time picker attribute."""
format: Optional[str] = Field( format: Optional[str] = Field(
None, None,
@@ -253,11 +282,18 @@ class UITimePicker(StatusMixin, UIComponent):
description="The step of the second input", description="The step of the second input",
) )
ui_type: Literal["time_picker"] = Field("time_picker", frozen=True)
class UITreeSelect(StatusMixin, UIComponent): attr: Optional[UIAttribute] = Field(
None,
description="The attributes of the component",
)
class UITreeSelect(UICascader):
"""Tree select component.""" """Tree select component."""
ui_type: Literal["tree_select"] = Field("tree_select", frozen=True) ui_type: Literal["tree_select"] = Field("tree_select", frozen=True) # type: ignore
def check_parameter(self, parameter_dict: Dict[str, Any]): def check_parameter(self, parameter_dict: Dict[str, Any]):
"""Check parameter.""" """Check parameter."""
@@ -271,19 +307,24 @@ class UITreeSelect(StatusMixin, UIComponent):
) )
class UIUpload(StatusMixin, UIComponent): class UIUpload(UIComponent):
"""Upload component.""" """Upload component."""
class UIAttribute(UIComponent.UIAttribute):
"""Upload attribute."""
max_count: Optional[int] = Field(
None,
description="The maximum number of files that can be uploaded",
)
ui_type: Literal["upload"] = Field("upload", frozen=True) ui_type: Literal["upload"] = Field("upload", frozen=True)
max_file_size: Optional[int] = Field( max_file_size: Optional[int] = Field(
None, None,
description="The maximum size of the file, in bytes", description="The maximum size of the file, in bytes",
) )
max_count: Optional[int] = Field(
None,
description="The maximum number of files that can be uploaded",
)
file_types: Optional[List[str]] = Field( file_types: Optional[List[str]] = Field(
None, None,
description="The file types that can be accepted", description="The file types that can be accepted",
@@ -346,3 +387,13 @@ class UICodeEditor(UITextArea):
"python", "python",
description="The language of the code", description="The language of the code",
) )
class DefaultUITextArea(UITextArea):
"""Default text area component."""
autosize: Union[bool, UITextArea.AutoSize] = Field(
default_factory=lambda: UITextArea.AutoSize(min_rows=2, max_rows=40),
description="Whether the height of the textarea automatically adjusts based "
"on the content",
)

View File

@@ -2,7 +2,7 @@
import inspect import inspect
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any, Callable, Dict, List from typing import Any, Callable, Dict, List, Optional
from dbgpt._private.pydantic import BaseModel, Field, model_validator from dbgpt._private.pydantic import BaseModel, Field, model_validator
from dbgpt.core.interface.serialization import Serializable from dbgpt.core.interface.serialization import Serializable
@@ -16,6 +16,9 @@ class OptionValue(Serializable, BaseModel):
label: str = Field(..., description="The label of the option") label: str = Field(..., description="The label of the option")
name: str = Field(..., description="The name of the option") name: str = Field(..., description="The name of the option")
value: Any = Field(..., description="The value of the option") value: Any = Field(..., description="The value of the option")
children: Optional[List["OptionValue"]] = Field(
None, description="The children of the option"
)
def to_dict(self) -> Dict: def to_dict(self) -> Dict:
"""Convert current metadata to json dict.""" """Convert current metadata to json dict."""

View File

@@ -24,6 +24,7 @@ from dbgpt.core.awel.flow import (
OperatorType, OperatorType,
Parameter, Parameter,
ViewMetadata, ViewMetadata,
ui,
) )
from dbgpt.core.interface.llm import ( from dbgpt.core.interface.llm import (
LLMClient, LLMClient,
@@ -69,6 +70,10 @@ class RequestBuilderOperator(MapOperator[RequestInput, ModelRequest]):
optional=True, optional=True,
default=None, default=None,
description=_("The temperature of the model request."), description=_("The temperature of the model request."),
ui=ui.UISlider(
show_input=True,
attr=ui.UISlider.UIAttribute(min=0.0, max=2.0, step=0.1),
),
), ),
Parameter.build_from( Parameter.build_from(
_("Max New Tokens"), _("Max New Tokens"),

View File

@@ -1,4 +1,5 @@
"""The prompt operator.""" """The prompt operator."""
from abc import ABC from abc import ABC
from typing import Any, Dict, List, Optional, Union from typing import Any, Dict, List, Optional, Union
@@ -18,6 +19,7 @@ from dbgpt.core.awel.flow import (
ResourceCategory, ResourceCategory,
ViewMetadata, ViewMetadata,
register_resource, register_resource,
ui,
) )
from dbgpt.core.interface.message import BaseMessage from dbgpt.core.interface.message import BaseMessage
from dbgpt.core.interface.operators.llm_operator import BaseLLM from dbgpt.core.interface.operators.llm_operator import BaseLLM
@@ -48,6 +50,7 @@ from dbgpt.util.i18n_utils import _
optional=True, optional=True,
default="You are a helpful AI Assistant.", default="You are a helpful AI Assistant.",
description=_("The system message."), description=_("The system message."),
ui=ui.DefaultUITextArea(),
), ),
Parameter.build_from( Parameter.build_from(
label=_("Message placeholder"), label=_("Message placeholder"),
@@ -65,6 +68,7 @@ from dbgpt.util.i18n_utils import _
default="{user_input}", default="{user_input}",
placeholder="{user_input}", placeholder="{user_input}",
description=_("The human message."), description=_("The human message."),
ui=ui.DefaultUITextArea(),
), ),
], ],
) )

View File

@@ -209,7 +209,7 @@ async def query_page(
@router.get("/nodes", dependencies=[Depends(check_api_key)]) @router.get("/nodes", dependencies=[Depends(check_api_key)])
async def get_nodes() -> Result[List[Union[ViewMetadata, ResourceMetadata]]]: async def get_nodes():
"""Get the operator or resource nodes """Get the operator or resource nodes
Returns: Returns:
@@ -218,7 +218,8 @@ async def get_nodes() -> Result[List[Union[ViewMetadata, ResourceMetadata]]]:
""" """
from dbgpt.core.awel.flow.base import _OPERATOR_REGISTRY from dbgpt.core.awel.flow.base import _OPERATOR_REGISTRY
return Result.succ(_OPERATOR_REGISTRY.metadata_list()) metadata_list = _OPERATOR_REGISTRY.metadata_list()
return Result.succ(metadata_list)
def init_endpoints(system_app: SystemApp) -> None: def init_endpoints(system_app: SystemApp) -> None:

View File

@@ -0,0 +1,583 @@
"""Some UI components for the AWEL flow."""
import logging
from typing import List, Optional
from dbgpt.core.awel import MapOperator
from dbgpt.core.awel.flow import (
IOField,
OperatorCategory,
OptionValue,
Parameter,
ViewMetadata,
ui,
)
logger = logging.getLogger(__name__)
class ExampleFlowCascaderOperator(MapOperator[str, str]):
"""An example flow operator that includes a cascader as parameter."""
metadata = ViewMetadata(
label="Example Flow Cascader",
name="example_flow_cascader",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a cascader as parameter.",
parameters=[
Parameter.build_from(
"Address Selector",
"address",
type=str,
is_list=True,
optional=True,
default=None,
placeholder="Select the address",
description="The address of the location.",
options=[
OptionValue(
label="Zhejiang",
name="zhejiang",
value="zhejiang",
children=[
OptionValue(
label="Hangzhou",
name="hangzhou",
value="hangzhou",
children=[
OptionValue(
label="Xihu",
name="xihu",
value="xihu",
),
OptionValue(
label="Feilaifeng",
name="feilaifeng",
value="feilaifeng",
),
],
),
],
),
OptionValue(
label="Jiangsu",
name="jiangsu",
value="jiangsu",
children=[
OptionValue(
label="Nanjing",
name="nanjing",
value="nanjing",
children=[
OptionValue(
label="Zhonghua Gate",
name="zhonghuamen",
value="zhonghuamen",
),
OptionValue(
label="Zhongshanling",
name="zhongshanling",
value="zhongshanling",
),
],
),
],
),
],
ui=ui.UICascader(attr=ui.UICascader.UIAttribute(show_search=True)),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"Address",
"address",
str,
description="User's address.",
)
],
)
def __int__(self, address: Optional[List[str]] = None, **kwargs):
super().__init__(**kwargs)
self.address = address or []
async def map(self, user_name: str) -> str:
"""Map the user name to the address."""
full_address_str = " ".join(self.address)
return "Your name is %s, and your address is %s." % (
user_name,
full_address_str,
)
class ExampleFlowCheckboxOperator(MapOperator[str, str]):
"""An example flow operator that includes a checkbox as parameter."""
metadata = ViewMetadata(
label="Example Flow Checkbox",
name="example_flow_checkbox",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a checkbox as parameter.",
parameters=[
Parameter.build_from(
"Fruits Selector",
"fruits",
type=str,
is_list=True,
optional=True,
default=None,
placeholder="Select the fruits",
description="The fruits you like.",
options=[
OptionValue(label="Apple", name="apple", value="apple"),
OptionValue(label="Banana", name="banana", value="banana"),
OptionValue(label="Orange", name="orange", value="orange"),
OptionValue(label="Pear", name="pear", value="pear"),
],
ui=ui.UICheckbox(attr=ui.UICheckbox.UIAttribute(show_search=True)),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"Fruits",
"fruits",
str,
description="User's favorite fruits.",
)
],
)
def __init__(self, fruits: Optional[List[str]] = None, **kwargs):
super().__init__(**kwargs)
self.fruits = fruits or []
async def map(self, user_name: str) -> str:
"""Map the user name to the fruits."""
return "Your name is %s, and you like %s." % (user_name, ", ".join(self.fruits))
class ExampleFlowDatePickerOperator(MapOperator[str, str]):
"""An example flow operator that includes a date picker as parameter."""
metadata = ViewMetadata(
label="Example Flow Date Picker",
name="example_flow_date_picker",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a date picker as parameter.",
parameters=[
Parameter.build_from(
"Date Selector",
"date",
type=str,
placeholder="Select the date",
description="The date you choose.",
ui=ui.UIDatePicker(
attr=ui.UIDatePicker.UIAttribute(placement="bottomLeft")
),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"Date",
"date",
str,
description="User's selected date.",
)
],
)
def __init__(self, date: str, **kwargs):
super().__init__(**kwargs)
self.date = date
async def map(self, user_name: str) -> str:
"""Map the user name to the date."""
return "Your name is %s, and you choose the date %s." % (user_name, self.date)
class ExampleFlowInputOperator(MapOperator[str, str]):
"""An example flow operator that includes an input as parameter."""
metadata = ViewMetadata(
label="Example Flow Input",
name="example_flow_input",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a input as parameter.",
parameters=[
Parameter.build_from(
"Your hobby",
"hobby",
type=str,
placeholder="Please input your hobby",
description="The hobby you like.",
ui=ui.UIInput(
attr=ui.UIInput.UIAttribute(
prefix="icon:UserOutlined", show_count=True, maxlength=200
)
),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"User Hobby",
"hobby",
str,
description="User's hobby.",
)
],
)
def __init__(self, hobby: str, **kwargs):
super().__init__(**kwargs)
self.hobby = hobby
async def map(self, user_name: str) -> str:
"""Map the user name to the input."""
return "Your name is %s, and your hobby is %s." % (user_name, self.hobby)
class ExampleFlowTextAreaOperator(MapOperator[str, str]):
"""An example flow operator that includes a text area as parameter."""
metadata = ViewMetadata(
label="Example Flow Text Area",
name="example_flow_text_area",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a text area as parameter.",
parameters=[
Parameter.build_from(
"Your comment",
"comment",
type=str,
placeholder="Please input your comment",
description="The comment you want to say.",
ui=ui.UITextArea(
attr=ui.UITextArea.UIAttribute(show_count=True, maxlength=1000),
autosize=ui.UITextArea.AutoSize(min_rows=2, max_rows=6),
),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"User Comment",
"comment",
str,
description="User's comment.",
)
],
)
def __init__(self, comment: str, **kwargs):
super().__init__(**kwargs)
self.comment = comment
async def map(self, user_name: str) -> str:
"""Map the user name to the text area."""
return "Your name is %s, and your comment is %s." % (user_name, self.comment)
class ExampleFlowSliderOperator(MapOperator[float, float]):
metadata = ViewMetadata(
label="Example Flow Slider",
name="example_flow_slider",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a slider as parameter.",
parameters=[
Parameter.build_from(
"Default Temperature",
"default_temperature",
type=float,
optional=True,
default=0.7,
placeholder="Set the default temperature, e.g., 0.7",
description="The default temperature to pass to the LLM.",
ui=ui.UISlider(
show_input=True,
attr=ui.UISlider.UIAttribute(min=0.0, max=2.0, step=0.1),
),
)
],
inputs=[
IOField.build_from(
"Temperature",
"temperature",
float,
description="The temperature.",
)
],
outputs=[
IOField.build_from(
"Temperature",
"temperature",
float,
description="The temperature to pass to the LLM.",
)
],
)
def __init__(self, default_temperature: float = 0.7, **kwargs):
super().__init__(**kwargs)
self.default_temperature = default_temperature
async def map(self, temperature: float) -> float:
"""Map the temperature to the result."""
if temperature < 0.0 or temperature > 2.0:
logger.warning("Temperature out of range: %s", temperature)
return self.default_temperature
else:
return temperature
class ExampleFlowSliderListOperator(MapOperator[float, float]):
"""An example flow operator that includes a slider list as parameter."""
metadata = ViewMetadata(
label="Example Flow Slider List",
name="example_flow_slider_list",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a slider list as parameter.",
parameters=[
Parameter.build_from(
"Temperature Selector",
"temperature_range",
type=float,
is_list=True,
optional=True,
default=None,
placeholder="Set the temperature, e.g., [0.1, 0.9]",
description="The temperature range to pass to the LLM.",
ui=ui.UISlider(
show_input=True,
attr=ui.UISlider.UIAttribute(min=0.0, max=2.0, step=0.1),
),
)
],
inputs=[
IOField.build_from(
"Temperature",
"temperature",
float,
description="The temperature.",
)
],
outputs=[
IOField.build_from(
"Temperature",
"temperature",
float,
description="The temperature to pass to the LLM.",
)
],
)
def __init__(self, temperature_range: Optional[List[float]] = None, **kwargs):
super().__init__(**kwargs)
temperature_range = temperature_range or [0.1, 0.9]
if temperature_range and len(temperature_range) != 2:
raise ValueError("The length of temperature range must be 2.")
self.temperature_range = temperature_range
async def map(self, temperature: float) -> float:
"""Map the temperature to the result."""
min_temperature, max_temperature = self.temperature_range
if temperature < min_temperature or temperature > max_temperature:
logger.warning(
"Temperature out of range: %s, min: %s, max: %s",
temperature,
min_temperature,
max_temperature,
)
return min_temperature
return temperature
class ExampleFlowTimePickerOperator(MapOperator[str, str]):
"""An example flow operator that includes a time picker as parameter."""
metadata = ViewMetadata(
label="Example Flow Time Picker",
name="example_flow_time_picker",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a time picker as parameter.",
parameters=[
Parameter.build_from(
"Time Selector",
"time",
type=str,
placeholder="Select the time",
description="The time you choose.",
ui=ui.UITimePicker(
attr=ui.UITimePicker.UIAttribute(
format="HH:mm:ss", hour_step=2, minute_step=10, second_step=10
),
),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"Time",
"time",
str,
description="User's selected time.",
)
],
)
def __init__(self, time: str, **kwargs):
super().__init__(**kwargs)
self.time = time
async def map(self, user_name: str) -> str:
"""Map the user name to the time."""
return "Your name is %s, and you choose the time %s." % (user_name, self.time)
class ExampleFlowTreeSelectOperator(MapOperator[str, str]):
"""An example flow operator that includes a tree select as parameter."""
metadata = ViewMetadata(
label="Example Flow Tree Select",
name="example_flow_tree_select",
category=OperatorCategory.EXAMPLE,
description="An example flow operator that includes a tree select as parameter.",
parameters=[
Parameter.build_from(
"Address Selector",
"address",
type=str,
is_list=True,
optional=True,
default=None,
placeholder="Select the address",
description="The address of the location.",
options=[
OptionValue(
label="Zhejiang",
name="zhejiang",
value="zhejiang",
children=[
OptionValue(
label="Hangzhou",
name="hangzhou",
value="hangzhou",
children=[
OptionValue(
label="Xihu",
name="xihu",
value="xihu",
),
OptionValue(
label="Feilaifeng",
name="feilaifeng",
value="feilaifeng",
),
],
),
],
),
OptionValue(
label="Jiangsu",
name="jiangsu",
value="jiangsu",
children=[
OptionValue(
label="Nanjing",
name="nanjing",
value="nanjing",
children=[
OptionValue(
label="Zhonghua Gate",
name="zhonghuamen",
value="zhonghuamen",
),
OptionValue(
label="Zhongshanling",
name="zhongshanling",
value="zhongshanling",
),
],
),
],
),
],
ui=ui.UITreeSelect(attr=ui.UITreeSelect.UIAttribute(show_search=True)),
)
],
inputs=[
IOField.build_from(
"User Name",
"user_name",
str,
description="The name of the user.",
)
],
outputs=[
IOField.build_from(
"Address",
"address",
str,
description="User's address.",
)
],
)
def __int__(self, address: Optional[List[str]] = None, **kwargs):
super().__init__(**kwargs)
self.address = address or []
async def map(self, user_name: str) -> str:
"""Map the user name to the address."""
full_address_str = " ".join(self.address)
return "Your name is %s, and your address is %s." % (
user_name,
full_address_str,
)