Spaces:
Running
Running
feat: add Flow component
Browse files- app.py +2 -0
- components/Chatbot/README-zh_CN.md +2 -2
- components/Chatbot/README.md +1 -1
- components/Chatbot/demos/chart.py +1 -0
- components/Docs.py +30 -11
- components/Flow/README-zh_CN.md +109 -0
- components/Flow/README.md +108 -0
- components/Flow/app.py +6 -0
- components/Flow/define_schema-zh_CN.md +266 -0
- components/Flow/define_schema.md +262 -0
- components/Flow/demos/basic.py +34 -0
- components/Flow/demos/component_options.py +104 -0
- components/Flow/demos/custom_node_type.py +69 -0
- components/Flow/schema/agents_schema.json +66 -0
- components/Flow/schema/agents_schema.py +59 -0
- components/Markdown/README-zh_CN.md +2 -2
- components/Markdown/README.md +3 -3
- components/Markdown/demos/custom-tag2.py +19 -2
- components/MultimodalInput/README.md +1 -1
- components/parse_markdown.py +10 -4
- components/resources/custom_components/custom_select.js +16 -13
- modelscope_studio-0.1.4-py3-none-any.whl → modelscope_studio-0.2.0-py3-none-any.whl +2 -2
- requirements.txt +1 -1
- src/pyproject.toml +4 -1
app.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
import gradio as gr
|
2 |
from components.Chatbot.app import docs as chatbot_docs
|
3 |
from components.Docs import Docs
|
|
|
4 |
from components.Markdown.app import docs as markdown_docs
|
5 |
from components.MultimodalInput.app import docs as multimodel_input_docs
|
6 |
from components.WaterfallGallery.app import docs as waterfall_gallery_docs
|
@@ -13,6 +14,7 @@ docs = [
|
|
13 |
["Markdown", markdown_docs],
|
14 |
["MultimodalInput", multimodel_input_docs],
|
15 |
["WaterfallGallery", waterfall_gallery_docs],
|
|
|
16 |
]
|
17 |
|
18 |
with gr.Blocks() as demo:
|
|
|
1 |
import gradio as gr
|
2 |
from components.Chatbot.app import docs as chatbot_docs
|
3 |
from components.Docs import Docs
|
4 |
+
from components.Flow.app import docs as flow_docs
|
5 |
from components.Markdown.app import docs as markdown_docs
|
6 |
from components.MultimodalInput.app import docs as multimodel_input_docs
|
7 |
from components.WaterfallGallery.app import docs as waterfall_gallery_docs
|
|
|
14 |
["Markdown", markdown_docs],
|
15 |
["MultimodalInput", multimodel_input_docs],
|
16 |
["WaterfallGallery", waterfall_gallery_docs],
|
17 |
+
["Flow", flow_docs],
|
18 |
]
|
19 |
|
20 |
with gr.Blocks() as demo:
|
components/Chatbot/README-zh_CN.md
CHANGED
@@ -89,7 +89,7 @@ class MultimodalMessage(GradioModel):
|
|
89 |
# message 容器的 elem id
|
90 |
elem_id: Optional[str] = None
|
91 |
# message 容器的 elem classes
|
92 |
-
elem_classes: Optional[
|
93 |
name: Optional[str] = None
|
94 |
text: Optional[str] = None
|
95 |
flushing: Optional[bool] = None
|
@@ -123,7 +123,7 @@ class ChatbotData(GradioRootModel):
|
|
123 |
| llm_thinking_presets | list\[dict\] | \[\] | llm 思考链路解析预设,可以将 llm 调用工具的输出格式转为固定的前端展示格式,需要从modelscope_studio.Chatbot.llm_thinking_presets引入,目前支持:qwen |
|
124 |
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户定义自定义标签,并通过 js 控制标签渲染样式与触发 python 事件。 |
|
125 |
|
126 |
-
**
|
127 |
|
128 |
```python
|
129 |
class CustomComponentDict(TypedDict):
|
|
|
89 |
# message 容器的 elem id
|
90 |
elem_id: Optional[str] = None
|
91 |
# message 容器的 elem classes
|
92 |
+
elem_classes: Optional[List[str] | str] = None
|
93 |
name: Optional[str] = None
|
94 |
text: Optional[str] = None
|
95 |
flushing: Optional[bool] = None
|
|
|
123 |
| llm_thinking_presets | list\[dict\] | \[\] | llm 思考链路解析预设,可以将 llm 调用工具的输出格式转为固定的前端展示格式,需要从modelscope_studio.Chatbot.llm_thinking_presets引入,目前支持:qwen |
|
124 |
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户定义自定义标签,并通过 js 控制标签渲染样式与触发 python 事件。 |
|
125 |
|
126 |
+
**CustomComponentDict 定义如下**
|
127 |
|
128 |
```python
|
129 |
class CustomComponentDict(TypedDict):
|
components/Chatbot/README.md
CHANGED
@@ -88,7 +88,7 @@ class MultimodalMessage(GradioModel):
|
|
88 |
# elem id of message container
|
89 |
elem_id: Optional[str] = None
|
90 |
# elem classes of message container
|
91 |
-
elem_classes: Optional[
|
92 |
name: Optional[str] = None
|
93 |
text: Optional[str] = None
|
94 |
flushing: Optional[bool] = None
|
|
|
88 |
# elem id of message container
|
89 |
elem_id: Optional[str] = None
|
90 |
# elem classes of message container
|
91 |
+
elem_classes: Optional[List[str] | str] = None
|
92 |
name: Optional[str] = None
|
93 |
text: Optional[str] = None
|
94 |
flushing: Optional[bool] = None
|
components/Chatbot/demos/chart.py
CHANGED
@@ -35,6 +35,7 @@ Chart:
|
|
35 |
with gr.Blocks() as demo:
|
36 |
mgr.Chatbot(
|
37 |
value=conversation,
|
|
|
38 |
height=600,
|
39 |
)
|
40 |
|
|
|
35 |
with gr.Blocks() as demo:
|
36 |
mgr.Chatbot(
|
37 |
value=conversation,
|
38 |
+
flushing=False,
|
39 |
height=600,
|
40 |
)
|
41 |
|
components/Docs.py
CHANGED
@@ -49,7 +49,7 @@ def get_demo_modules(file_path: str):
|
|
49 |
demos = [
|
50 |
demo for demo in list_demos(
|
51 |
os.path.join(os.path.dirname(file_path), "demos"))
|
52 |
-
if demo.endswith(".py")
|
53 |
]
|
54 |
demo_modules = {}
|
55 |
for demo in demos:
|
@@ -93,23 +93,41 @@ class Docs:
|
|
93 |
"r") as f:
|
94 |
return f.read()
|
95 |
|
96 |
-
def render_demo(self,
|
|
|
|
|
|
|
|
|
97 |
content = self.read_file(f"./demos/{demo_name}.py")
|
98 |
module = self.demo_modules[demo_name]
|
99 |
with gr.Accordion("Show Demo", open=False):
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
{prefix}
|
104 |
````python
|
105 |
{content}
|
106 |
````
|
107 |
-
{suffix}
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
with gr.Column():
|
112 |
module.demo.render()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
def render_markdown(self,
|
115 |
markdown_file,
|
@@ -129,7 +147,8 @@ class Docs:
|
|
129 |
elif item["type"] == "demo":
|
130 |
self.render_demo(item["name"],
|
131 |
prefix=item["prefix"],
|
132 |
-
suffix=item["suffix"]
|
|
|
133 |
|
134 |
def render(self, components_tabs=None):
|
135 |
|
|
|
49 |
demos = [
|
50 |
demo for demo in list_demos(
|
51 |
os.path.join(os.path.dirname(file_path), "demos"))
|
52 |
+
if demo.endswith(".py") and not demo.startswith("__")
|
53 |
]
|
54 |
demo_modules = {}
|
55 |
for demo in demos:
|
|
|
93 |
"r") as f:
|
94 |
return f.read()
|
95 |
|
96 |
+
def render_demo(self,
|
97 |
+
demo_name,
|
98 |
+
code_position='left',
|
99 |
+
prefix='',
|
100 |
+
suffix=''):
|
101 |
content = self.read_file(f"./demos/{demo_name}.py")
|
102 |
module = self.demo_modules[demo_name]
|
103 |
with gr.Accordion("Show Demo", open=False):
|
104 |
+
|
105 |
+
def render_code():
|
106 |
+
mgr.Markdown(f"""{prefix}
|
|
|
107 |
````python
|
108 |
{content}
|
109 |
````
|
110 |
+
{suffix}""",
|
111 |
+
header_links=True,
|
112 |
+
custom_components=custom_components)
|
113 |
+
|
114 |
+
if code_position == 'top':
|
115 |
+
with gr.Row():
|
116 |
+
with gr.Column():
|
117 |
+
render_code()
|
118 |
+
with gr.Row():
|
119 |
+
if code_position == 'left':
|
120 |
+
with gr.Column():
|
121 |
+
render_code()
|
122 |
with gr.Column():
|
123 |
module.demo.render()
|
124 |
+
if code_position == 'right':
|
125 |
+
with gr.Column():
|
126 |
+
render_code()
|
127 |
+
if code_position == 'bottom':
|
128 |
+
with gr.Row():
|
129 |
+
with gr.Column():
|
130 |
+
render_code()
|
131 |
|
132 |
def render_markdown(self,
|
133 |
markdown_file,
|
|
|
147 |
elif item["type"] == "demo":
|
148 |
self.render_demo(item["name"],
|
149 |
prefix=item["prefix"],
|
150 |
+
suffix=item["suffix"],
|
151 |
+
code_position=item["code_position"])
|
152 |
|
153 |
def render(self, components_tabs=None):
|
154 |
|
components/Flow/README-zh_CN.md
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Flow
|
2 |
+
|
3 |
+
基于 [reactflow](https://reactflow.dev/) 实现的 Flow 组件。
|
4 |
+
|
5 |
+
- 支持通过 schema 自定义渲染节点
|
6 |
+
- 支持自定义节点的渲染组件,并与 Python 事件交互
|
7 |
+
|
8 |
+
## 如何使用
|
9 |
+
|
10 |
+
### 定义 schema 节点 (重要)
|
11 |
+
|
12 |
+
详见:<tab-link tab="define_schema">Define Schema</tab-link>
|
13 |
+
|
14 |
+
### 基本使用
|
15 |
+
|
16 |
+
<demo name="basic" code-position="bottom"></demo>
|
17 |
+
|
18 |
+
### 组件配置项
|
19 |
+
|
20 |
+
<demo name="component_options" code-position="bottom"></demo>
|
21 |
+
|
22 |
+
### 自定义节点类型(高阶用法,需要了解前端知识)
|
23 |
+
|
24 |
+
<demo name="custom_node_type" code-position="bottom"></demo>
|
25 |
+
|
26 |
+
## API 及参数列表
|
27 |
+
|
28 |
+
### value
|
29 |
+
|
30 |
+
接口定义:
|
31 |
+
|
32 |
+
```python
|
33 |
+
class NodePosition(GradioModel):
|
34 |
+
x: Optional[int] = 0
|
35 |
+
y: Optional[int] = 0
|
36 |
+
|
37 |
+
|
38 |
+
class Node(GradioModel):
|
39 |
+
id: Optional[str] = None
|
40 |
+
name: str
|
41 |
+
title: Optional[str] = None
|
42 |
+
position: Optional[Union[NodePosition, dict]] = None
|
43 |
+
data: Optional[dict] = None
|
44 |
+
|
45 |
+
class EdgePort(GradioModel):
|
46 |
+
attr: Optional[str] = None
|
47 |
+
attrItemIndex: Optional[int] = None
|
48 |
+
handleIndex: Optional[int] = None
|
49 |
+
|
50 |
+
class Edge(GradioModel):
|
51 |
+
id: Optional[str] = None
|
52 |
+
source: str
|
53 |
+
target: str
|
54 |
+
sourcePort: Optional[Union[EdgePort, dict]] = None
|
55 |
+
targetPort: Optional[Union[EdgePort, dict]] = None
|
56 |
+
|
57 |
+
|
58 |
+
class FlowData(GradioModel):
|
59 |
+
nodes: Optional[List[Union[Node, dict]]] = []
|
60 |
+
edges: Optional[List[Union[Edge, dict]]] = []
|
61 |
+
|
62 |
+
```
|
63 |
+
|
64 |
+
### props
|
65 |
+
|
66 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
67 |
+
| ------------------- | --------------------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
68 |
+
| height | int \| str | 600 | Flow 组件高度。 |
|
69 |
+
| sync_on_data_change | bool | None | 是否仅在数据更改时同步 Python 值(例如:节点属性、节点计数、边缘计数、连接端口等,不包括节点位置)。 如果您想要更好的页面性能而不是完整数据同步,则应将其设置为 True。 |
|
70 |
+
| schema | FlowSchemaDict \| dict | None | 定义 Flow 组件的 nodes 与 edges。 |
|
71 |
+
| show_sidebar | bool | True | 是否展示侧 Flow 组件侧边栏。 |
|
72 |
+
| show_minimap | bool | True | 是否展示侧 Flow 组件小地图。 |
|
73 |
+
| show_controls | bool | True | 是否展示侧Flow 组件控制栏。 |
|
74 |
+
| background_props | BackgroundPropsDict \| dict CustomComponentDict 定义见下方 | None | 修改 Flow组件背景,详见 BackgroundPropsDict 类型。 |
|
75 |
+
| min_zoom | int | 0.1 | Flow 组件最小缩放倍率。 |
|
76 |
+
| max_zoom | int | 2 | Flow 组件最大缩放倍率。 |
|
77 |
+
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户自定义节点类型,并通过 js 控制渲染样式与触发 python 事件。 |
|
78 |
+
|
79 |
+
**BackgroundPropsDict 定义如下**
|
80 |
+
|
81 |
+
```python
|
82 |
+
class BackgroundPropsDict(TypedDict):
|
83 |
+
color: Optional[str]
|
84 |
+
className: Optional[str]
|
85 |
+
# The gap between patterns. Passing in a tuple allows you to control the x and y gap independently.
|
86 |
+
gap: Optional[Union[int, Tuple[int, int]]]
|
87 |
+
# The radius of each dot or the size of each rectangle if BackgroundVariant.Dots or BackgroundVariant.Cross is used. This defaults to 1 or 6 respectively, or ignored if BackgroundVariant.Lines is used.
|
88 |
+
size: Optional[int]
|
89 |
+
offset: Optional[int]
|
90 |
+
lineWidth: Optional[int]
|
91 |
+
variant: Optional[Literal['dots', 'lines', 'cross']]
|
92 |
+
```
|
93 |
+
|
94 |
+
**CustomComponentDict 定义如下**
|
95 |
+
|
96 |
+
```python
|
97 |
+
class CustomComponentDict(TypedDict):
|
98 |
+
props: Optional[List[str]]
|
99 |
+
template: Optional[str]
|
100 |
+
js: Optional[str]
|
101 |
+
```
|
102 |
+
|
103 |
+
### event listeners
|
104 |
+
|
105 |
+
| 事件 | 描述 |
|
106 |
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
107 |
+
| `mgr.Flow.change(fn, ···)` | 当 value 更新时触发,如果 sync_on_data_change 值为 True 时,此时 flow 的实际数据可能并不是实时的,建议监听 data_change 事件。 |
|
108 |
+
| `mgr.Flow.data_change(fn, ···)` | 当在数据更改时触发(例如:节点属性、节点计数、边缘计数、连接端口等,不包括节点位置) |
|
109 |
+
| `mgr.Flow.custom(fn, ···)` | 自定义标签触发事件时触发,EventData 为:<br/> - id:当前触发节点 id。<br/> - node:当前触发节点类型。 <br/> - attr:当前触发节点属性。<br/> - index:当前触发节点属性索引,当节点属性为 list 时有值。<br/> - value:自定义传入的值。 |
|
components/Flow/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Flow
|
2 |
+
|
3 |
+
A Flow component implemented based on [reactflow](https://reactflow.dev/).
|
4 |
+
|
5 |
+
- Supports customization of node rendering through a schema.
|
6 |
+
- Allows for custom node render components with interaction from Python.
|
7 |
+
|
8 |
+
## How to Use
|
9 |
+
|
10 |
+
### Defining Schema Nodes (Important)
|
11 |
+
|
12 |
+
See: <tab-link tab="define_schema">Define Schema</tab-link>
|
13 |
+
|
14 |
+
### Basic Usage
|
15 |
+
|
16 |
+
<demo name="basic" code-position="bottom"></demo>
|
17 |
+
|
18 |
+
### Component Options
|
19 |
+
|
20 |
+
<demo name="component_options" code-position="bottom"></demo>
|
21 |
+
|
22 |
+
### Custom Node Types (Advanced usage, requires frontend knowledge)
|
23 |
+
|
24 |
+
<demo name="custom_node_type" code-position="bottom"></demo>
|
25 |
+
|
26 |
+
## API and Parameter List
|
27 |
+
|
28 |
+
### value
|
29 |
+
|
30 |
+
Interface definition:
|
31 |
+
|
32 |
+
```python
|
33 |
+
class NodePosition(GradioModel):
|
34 |
+
x: Optional[int] = 0
|
35 |
+
y: Optional[int] = 0
|
36 |
+
|
37 |
+
|
38 |
+
class Node(GradioModel):
|
39 |
+
id: Optional[str] = None
|
40 |
+
name: str
|
41 |
+
title: Optional[str] = None
|
42 |
+
position: Optional[Union[NodePosition, dict]] = None
|
43 |
+
data: Optional[dict] = None
|
44 |
+
|
45 |
+
class EdgePort(GradioModel):
|
46 |
+
attr: Optional[str] = None
|
47 |
+
attrItemIndex: Optional[int] = None
|
48 |
+
handleIndex: Optional[int] = None
|
49 |
+
|
50 |
+
class Edge(GradioModel):
|
51 |
+
id: Optional[str] = None
|
52 |
+
source: str
|
53 |
+
target: str
|
54 |
+
sourcePort: Optional[Union[EdgePort, dict]] = None
|
55 |
+
targetPort: Optional[Union[EdgePort, dict]] = None
|
56 |
+
|
57 |
+
|
58 |
+
class FlowData(GradioModel):
|
59 |
+
nodes: Optional[List[Union[Node, dict]]] = []
|
60 |
+
edges: Optional[List[Union[Edge, dict]]] = []
|
61 |
+
```
|
62 |
+
|
63 |
+
### props
|
64 |
+
|
65 |
+
| Property | Type | Default | Description |
|
66 |
+
| ------------------- | --------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
67 |
+
| height | int \| str | 600 | Height of the Flow component. |
|
68 |
+
| sync_on_data_change | bool | None | Whether to sync the Python value only on data change (e.g., node attributes, node count, edge count, connection ports, not including node positions). If you want better page performance without full data sync, set this to True. |
|
69 |
+
| schema | FlowSchemaDict \| dict | None | Defines the nodes and edges of the Flow component. |
|
70 |
+
| show_sidebar | bool | True | Whether to display the sidebar in the Flow component. |
|
71 |
+
| show_minimap | bool | True | Whether to display the minimap in the Flow component. |
|
72 |
+
| show_controls | bool | True | Whether to display the controls bar in the Flow component. |
|
73 |
+
| background_props | BackgroundPropsDict \| dict BackgroundPropsDict definition below | None | Modify the background of the Flow component, see the BackgroundPropsDict type. |
|
74 |
+
| min_zoom | int | 0.1 | Minimum zoom level for the Flow component. |
|
75 |
+
| max_zoom | int | 2 | Maximum zoom level for the Flow component. |
|
76 |
+
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict definition below | None | Supports user-defined custom tags and controls tag rendering styles and triggers Python events through js. |
|
77 |
+
|
78 |
+
**BackgroundPropsDict definition:**
|
79 |
+
|
80 |
+
```python
|
81 |
+
class BackgroundPropsDict(TypedDict):
|
82 |
+
color: Optional[str]
|
83 |
+
className: Optional[str]
|
84 |
+
# The gap between patterns. Passing in a tuple allows you to control the x and y gap independently.
|
85 |
+
gap: Optional[Union[int, Tuple[int, int]]]
|
86 |
+
# The radius of each dot or the size of each rectangle if BackgroundVariant.Dots or BackgroundVariant.Cross is used. This defaults to 1 or 6 respectively, or ignored if BackgroundVariant.Lines is used.
|
87 |
+
size: Optional[int]
|
88 |
+
offset: Optional[int]
|
89 |
+
lineWidth: Optional[int]
|
90 |
+
variant: Optional[Literal['dots', 'lines', 'cross']]
|
91 |
+
```
|
92 |
+
|
93 |
+
**CustomComponentDict definition:**
|
94 |
+
|
95 |
+
```python
|
96 |
+
class CustomComponentDict(TypedDict):
|
97 |
+
props: Optional[List[str]]
|
98 |
+
template: Optional[str]
|
99 |
+
js: Optional[str]
|
100 |
+
```
|
101 |
+
|
102 |
+
### Event Listeners
|
103 |
+
|
104 |
+
| Event | Description |
|
105 |
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
106 |
+
| `mgr.Flow.change(fn, ...)` | Triggers when the `value` updates. If `sync_on_data_change` is True, the actual data at this point might not be up-to-date; consider listening to the `data_change` event instead. |
|
107 |
+
| `mgr.Flow.data_change(fn, ...)` | Triggers when there's a data change (e.g., node attributes, node count, edge count, connection ports), but not node positions. |
|
108 |
+
| `mgr.Flow.custom(fn, ...)` | Triggers when a custom label event occurs. The `EventData` includes:<br/> - `id`: ID of the currently triggered node.<br/> - `node`: Type of the currently triggered node.<br/> - `attr`: Attributes of the currently triggered node.<br/> - `index`: Index of the attribute if it's a list.<br/> - `value`: Custom passed-in value. |
|
components/Flow/app.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from components.Docs import Docs
|
2 |
+
|
3 |
+
docs = Docs(__file__)
|
4 |
+
|
5 |
+
if __name__ == "__main__":
|
6 |
+
docs.render().queue().launch()
|
components/Flow/define_schema-zh_CN.md
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Define Schema
|
2 |
+
|
3 |
+
在使用 Flow 组件前,需要预先创建 Schema 定义 node 节点,schema 类型定义如下:
|
4 |
+
|
5 |
+
```ts
|
6 |
+
export interface FlowSchema {
|
7 |
+
nodes: FlowNodeSchema[];
|
8 |
+
}
|
9 |
+
|
10 |
+
export interface FlowNodeSchema {
|
11 |
+
/**
|
12 |
+
* 作为节点的唯一标识。必填。
|
13 |
+
*/
|
14 |
+
name: string;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* 节点显示图标。
|
18 |
+
*/
|
19 |
+
icon?: string;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* 节点标题,如果没有提供则默认使用 name。
|
23 |
+
*/
|
24 |
+
title?: string;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* 节点的简短描述。
|
28 |
+
*/
|
29 |
+
description?: string;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* 节点宽度。
|
33 |
+
*/
|
34 |
+
width?: number;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* 节点高度。
|
38 |
+
*/
|
39 |
+
height?: number;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* 显示/隐藏工具栏(删除、复制、重命名等)。
|
43 |
+
* @default true
|
44 |
+
*/
|
45 |
+
show_toolbar?: boolean;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* 启用/禁止添加更多此类节点实例。
|
49 |
+
* @default true
|
50 |
+
*/
|
51 |
+
addable?: boolean;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* 启用/禁止删除现有此类节点实例。
|
55 |
+
* @default true
|
56 |
+
*/
|
57 |
+
deletable?: boolean;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* 可以同时存在的此类节点的最大数量。
|
61 |
+
*/
|
62 |
+
max?: number;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* 可以同时存在的此类节点的最小数量。
|
66 |
+
*/
|
67 |
+
min?: number;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* 节点连接端口的配置。
|
71 |
+
*/
|
72 |
+
ports?: {
|
73 |
+
/**
|
74 |
+
* 节点作为连接的源端口。
|
75 |
+
* @default ['right']
|
76 |
+
*/
|
77 |
+
source?: Position[];
|
78 |
+
|
79 |
+
/**
|
80 |
+
* 允许此节点 source 端口连接到的其他节点或属性。默认为所有节点和属性。
|
81 |
+
* @default []
|
82 |
+
*/
|
83 |
+
sourceConnections?: PortConnection[];
|
84 |
+
|
85 |
+
/**
|
86 |
+
* 节点作为连接的目标端口。
|
87 |
+
* @default ['left']
|
88 |
+
*/
|
89 |
+
target?: Position[];
|
90 |
+
|
91 |
+
/**
|
92 |
+
* 其他允许连接到此节点 target 端口的节点或属性。默认为所有节点和属性
|
93 |
+
* @default []
|
94 |
+
*/
|
95 |
+
targetConnections?: PortConnection[];
|
96 |
+
};
|
97 |
+
|
98 |
+
/**
|
99 |
+
* 节点的属性配置。
|
100 |
+
*/
|
101 |
+
attrs?: FlowNodeAttrSchema[];
|
102 |
+
|
103 |
+
/**
|
104 |
+
* 创建新实例时节点属性的初始值。
|
105 |
+
*/
|
106 |
+
template?: {
|
107 |
+
/**
|
108 |
+
* 在`attrs`字段中与其名称相对应的属性值,例如 { "a": 1, "b": 2 }。
|
109 |
+
*/
|
110 |
+
attrs?: Attrs;
|
111 |
+
};
|
112 |
+
}
|
113 |
+
|
114 |
+
export interface FlowNodeAttrSchema {
|
115 |
+
/**
|
116 |
+
* 唯一的属性名称,在 node data 中用作 key。必填。
|
117 |
+
*/
|
118 |
+
name: string;
|
119 |
+
|
120 |
+
/**
|
121 |
+
* 属性标题,如果没有提供则默认使用 name。
|
122 |
+
*/
|
123 |
+
title?: string;
|
124 |
+
|
125 |
+
/**
|
126 |
+
* 属性的简短描述
|
127 |
+
*/
|
128 |
+
description?: string;
|
129 |
+
|
130 |
+
/**
|
131 |
+
* 禁用用户编辑属性值。默认情况下,属性是可编辑的。
|
132 |
+
* @default false
|
133 |
+
*/
|
134 |
+
disabled?: boolean;
|
135 |
+
|
136 |
+
/**
|
137 |
+
* 属性输入类型。可以是内置的 Ant Design 组件或自定义组件之一。默认为'input'。
|
138 |
+
* @default 'input'
|
139 |
+
*/
|
140 |
+
type?:
|
141 |
+
| 'input'
|
142 |
+
| 'textarea'
|
143 |
+
| 'radio'
|
144 |
+
| 'checkbox'
|
145 |
+
| 'number'
|
146 |
+
| 'select'
|
147 |
+
| 'switch'
|
148 |
+
| 'upload'
|
149 |
+
// 自定义
|
150 |
+
| (string & {});
|
151 |
+
|
152 |
+
/**
|
153 |
+
* 针对所选组件类型的特定配置选项,支持 Ant Design 组件({@link https://ant.design/components/overview/})或自定义组件的属性。
|
154 |
+
*/
|
155 |
+
props?: Record<string, any>;
|
156 |
+
|
157 |
+
/**
|
158 |
+
* 节点属性连接端口的配置。
|
159 |
+
*/
|
160 |
+
ports?: {
|
161 |
+
/**
|
162 |
+
* 节点属性作为连接的源端口。
|
163 |
+
* @default []
|
164 |
+
*/
|
165 |
+
source?: Position[];
|
166 |
+
|
167 |
+
/**
|
168 |
+
* 允许此节点属性 source 端口连接到的其他节点或属性。
|
169 |
+
* @default []
|
170 |
+
*/
|
171 |
+
sourceConnections?: PortConnection[];
|
172 |
+
|
173 |
+
/**
|
174 |
+
* 节点属性作为连接的目标端口。
|
175 |
+
* @default []
|
176 |
+
*/
|
177 |
+
target?: Position[];
|
178 |
+
|
179 |
+
/**
|
180 |
+
* 其他允许连接到此节点属性 target 端口的节点或属性。
|
181 |
+
* @default []
|
182 |
+
*/
|
183 |
+
targetConnections?: PortConnection[];
|
184 |
+
};
|
185 |
+
|
186 |
+
/**
|
187 |
+
* 表示该属性是否为列表值。
|
188 |
+
* @default false
|
189 |
+
*/
|
190 |
+
list?:
|
191 |
+
| boolean
|
192 |
+
| {
|
193 |
+
/**
|
194 |
+
* 列表中每个 item 的端口配置。
|
195 |
+
*/
|
196 |
+
ports?: {
|
197 |
+
/**
|
198 |
+
* 列表 item 作为连接的源端口。
|
199 |
+
* @default []
|
200 |
+
*/
|
201 |
+
source?: Position[];
|
202 |
+
|
203 |
+
/**
|
204 |
+
* 允许此列表 item source 端口连接到的其他节点或属性。
|
205 |
+
* @default []
|
206 |
+
*/
|
207 |
+
sourceConnections?: PortConnection[];
|
208 |
+
|
209 |
+
/**
|
210 |
+
* 列表 item 作为连接的目标端口。
|
211 |
+
*/
|
212 |
+
target?: Position[];
|
213 |
+
|
214 |
+
/**
|
215 |
+
* 其他允许连接到此列表 item target 端口的节点或属性。
|
216 |
+
*/
|
217 |
+
targetConnections?: PortConnection[];
|
218 |
+
};
|
219 |
+
|
220 |
+
/**
|
221 |
+
* 列表中的最小 item 数量。
|
222 |
+
*/
|
223 |
+
min?: number;
|
224 |
+
|
225 |
+
/**
|
226 |
+
* 列表中的最大 item 数量。
|
227 |
+
*/
|
228 |
+
max?: number;
|
229 |
+
};
|
230 |
+
|
231 |
+
/**
|
232 |
+
* 启用/禁用手风琴 UI。
|
233 |
+
* @default true
|
234 |
+
*/
|
235 |
+
accordion?: boolean;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* 指定该属性值是否为必填项。默认情况为非必填项。
|
239 |
+
* @default false
|
240 |
+
*/
|
241 |
+
required?:
|
242 |
+
| boolean
|
243 |
+
| {
|
244 |
+
message?: string;
|
245 |
+
};
|
246 |
+
|
247 |
+
/**
|
248 |
+
* 使用 JSON schema 验证属性值。
|
249 |
+
*/
|
250 |
+
json_schema_validator?: Record<string, any>;
|
251 |
+
}
|
252 |
+
```
|
253 |
+
|
254 |
+
你可以通过 json 文件(推荐)或直接在 Python 端通过导出类型定义:
|
255 |
+
|
256 |
+
- 通过 json 定义:
|
257 |
+
|
258 |
+
```json
|
259 |
+
<file src="./schema/agents_schema.json"></file>
|
260 |
+
```
|
261 |
+
|
262 |
+
- 通过 Python 定义:
|
263 |
+
|
264 |
+
```python
|
265 |
+
<file src="./schema/agents_schema.py"></file>
|
266 |
+
```
|
components/Flow/define_schema.md
ADDED
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Define Schema
|
2 |
+
|
3 |
+
Before using the Flow component, need to create a Schema definition node in advance. The schema type is defined as follows:
|
4 |
+
|
5 |
+
```ts
|
6 |
+
export interface FlowSchema {
|
7 |
+
nodes: FlowNodeSchema[];
|
8 |
+
}
|
9 |
+
|
10 |
+
export interface FlowNodeSchema {
|
11 |
+
/**
|
12 |
+
* As a unique identifier for the node. Mandatory.
|
13 |
+
*/
|
14 |
+
name: string;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Display icon for the node.
|
18 |
+
*/
|
19 |
+
icon?: string;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Display title for the node, defaults to the node name if not provided.
|
23 |
+
*/
|
24 |
+
title?: string;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* A short description of the node's purpose.
|
28 |
+
*/
|
29 |
+
description?: string;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Width of the node.
|
33 |
+
*/
|
34 |
+
width?: number;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Height of the node.
|
38 |
+
*/
|
39 |
+
height?: number;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Shows/hides the toolbar (delete, copy, rename, etc.).
|
43 |
+
* @default true
|
44 |
+
*/
|
45 |
+
show_toolbar?: boolean;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Enables/disables adding more instances of this node.
|
49 |
+
* @default true
|
50 |
+
*/
|
51 |
+
addable?: boolean;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Enables/disables deleting existing instances of this node.
|
55 |
+
* @default true
|
56 |
+
*/
|
57 |
+
deletable?: boolean;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Maximum number of this node type that can exist simultaneously.
|
61 |
+
*/
|
62 |
+
max?: number;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Minimum number of this node type that must exist simultaneously.
|
66 |
+
*/
|
67 |
+
min?: number;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Configurations for the node's connection ports.
|
71 |
+
*/
|
72 |
+
ports?: {
|
73 |
+
/**
|
74 |
+
* Source ports for the node as a connection.
|
75 |
+
* @default ['right']
|
76 |
+
*/
|
77 |
+
source?: Position[];
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Allowed the source ports of this node to connect to other nodes or attributes. Defaults to all nodes and attributes
|
81 |
+
*/
|
82 |
+
sourceConnections?: PortConnection[];
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Target ports for the node as a connection
|
86 |
+
* @default ['left']
|
87 |
+
*/
|
88 |
+
target?: Position[];
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Allowed other nodes or attributes allowed to connect to the target ports of this node. Defaults to all nodes and attributes
|
92 |
+
*
|
93 |
+
*/
|
94 |
+
targetConnections?: PortConnection[];
|
95 |
+
};
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Configuration of the node's attributes.
|
99 |
+
*/
|
100 |
+
attrs?: FlowNodeAttrSchema[];
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Initial values for the node's attributes when creating a new instance.
|
104 |
+
*/
|
105 |
+
template?: {
|
106 |
+
/**
|
107 |
+
* Attribute values corresponding to their names in the `attrs` field, e.g., `{ "a": 1, "b": 2 }`.
|
108 |
+
*/
|
109 |
+
attrs?: Attrs;
|
110 |
+
};
|
111 |
+
}
|
112 |
+
|
113 |
+
export interface FlowNodeAttrSchema {
|
114 |
+
/**
|
115 |
+
* Unique attribute name used as a key in the node data. Mandatory.
|
116 |
+
*/
|
117 |
+
name: string;
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Display title for the attribute, defaults to the attribute name if not provided.
|
121 |
+
*/
|
122 |
+
title?: string;
|
123 |
+
|
124 |
+
/**
|
125 |
+
* A brief explanation about the attribute purpose.
|
126 |
+
*/
|
127 |
+
description?: string;
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Disables user editing of the attribute value. By default, attributes are editable.
|
131 |
+
* @default false
|
132 |
+
*/
|
133 |
+
disabled?: boolean;
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Attribute input type. Can be one of the built-in Ant Design components or a custom component. Defaults to 'input'.
|
137 |
+
* @default 'input'
|
138 |
+
*/
|
139 |
+
type?:
|
140 |
+
| 'input'
|
141 |
+
| 'textarea'
|
142 |
+
| 'radio'
|
143 |
+
| 'checkbox'
|
144 |
+
| 'number'
|
145 |
+
| 'select'
|
146 |
+
| 'switch'
|
147 |
+
| 'upload'
|
148 |
+
// custom
|
149 |
+
| (string & {});
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Configuration options specific to the chosen component type, supporting Ant Design ({@link https://ant.design/components/overview/}) or custom component properties.
|
153 |
+
*/
|
154 |
+
props?: Record<string, any>;
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Configurations for the node attribute ports.
|
158 |
+
*/
|
159 |
+
ports?: {
|
160 |
+
/**
|
161 |
+
* Source ports for the attribute as a connection.
|
162 |
+
* @default []
|
163 |
+
*/
|
164 |
+
source?: Position[];
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Allowed the source ports of this attribute to connect to other nodes or attributes. Defaults to all nodes and attributes
|
168 |
+
*/
|
169 |
+
sourceConnections?: PortConnection[];
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Target ports for the attribute as a connection
|
173 |
+
* @default []
|
174 |
+
*/
|
175 |
+
target?: Position[];
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Allowed other nodes or attributes allowed to connect to the target ports of this attribute. Defaults to all nodes and attributes
|
179 |
+
*/
|
180 |
+
targetConnections?: PortConnection[];
|
181 |
+
};
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Indicates whether the attribute is a list.
|
185 |
+
* @default false
|
186 |
+
*/
|
187 |
+
list?:
|
188 |
+
| boolean
|
189 |
+
| {
|
190 |
+
/**
|
191 |
+
* Port configurations for each item in the list.
|
192 |
+
*/
|
193 |
+
ports?: {
|
194 |
+
/**
|
195 |
+
* Source ports for the list item as a connection.
|
196 |
+
* @default []
|
197 |
+
*/
|
198 |
+
source?: Position[];
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Allowed the source ports of this list item to connect to other nodes or attributes. Defaults to all nodes and attributes
|
202 |
+
*/
|
203 |
+
sourceConnections?: PortConnection[];
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Target ports for the list item as a connection
|
207 |
+
*/
|
208 |
+
target?: Position[];
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Allowed other nodes or attributes allowed to connect to the target ports of this list item. Defaults to all nodes and attributes
|
212 |
+
*/
|
213 |
+
targetConnections?: PortConnection[];
|
214 |
+
};
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Minimum number of items in the list.
|
218 |
+
*/
|
219 |
+
min?: number;
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Maximum number of items in the list.
|
223 |
+
*/
|
224 |
+
max?: number;
|
225 |
+
};
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Enable/disable accordion UI.
|
229 |
+
* @default true
|
230 |
+
*/
|
231 |
+
accordion?: boolean;
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Specifies if the attribute value is mandatory. By default, attributes are optional.
|
235 |
+
* @default false
|
236 |
+
*/
|
237 |
+
required?:
|
238 |
+
| boolean
|
239 |
+
| {
|
240 |
+
message?: string;
|
241 |
+
};
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Validates attribute values using JSON schema.
|
245 |
+
*/
|
246 |
+
json_schema_validator?: Record<string, any>;
|
247 |
+
}
|
248 |
+
```
|
249 |
+
|
250 |
+
You can define the schema by a json file (recommended) or directly on the Python by the exported types:
|
251 |
+
|
252 |
+
- Defined by json:
|
253 |
+
|
254 |
+
```json
|
255 |
+
<file src="./schema/agents_schema.json"></file>
|
256 |
+
```
|
257 |
+
|
258 |
+
- Defined by Python:
|
259 |
+
|
260 |
+
```python
|
261 |
+
<file src="./schema/agents_schema.py"></file>
|
262 |
+
```
|
components/Flow/demos/basic.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_studio as mgr
|
7 |
+
from modelscope_studio.components.Flow import Edge, Node
|
8 |
+
|
9 |
+
with open((os.path.join(os.path.dirname(__file__),
|
10 |
+
"../schema/agents_schema.json"))) as f:
|
11 |
+
schema = json.load(f)
|
12 |
+
|
13 |
+
# define the initial value of the flow
|
14 |
+
data = {
|
15 |
+
"nodes": [
|
16 |
+
Node(id="start-node", name="start", position=dict(x=0, y=0)),
|
17 |
+
Node(name="agent",
|
18 |
+
position=dict(x=200, y=0),
|
19 |
+
data=dict(condition=['']))
|
20 |
+
],
|
21 |
+
"edges": [Edge(source='start-node', target="initial-agent-node")],
|
22 |
+
}
|
23 |
+
|
24 |
+
|
25 |
+
def on_data_change(_flow):
|
26 |
+
print(_flow)
|
27 |
+
|
28 |
+
|
29 |
+
with gr.Blocks() as demo:
|
30 |
+
flow = mgr.Flow(value=data, schema=schema, sync_on_data_change=True)
|
31 |
+
flow.data_change(fn=on_data_change, inputs=[flow])
|
32 |
+
|
33 |
+
if __name__ == "__main__":
|
34 |
+
demo.queue().launch()
|
components/Flow/demos/component_options.py
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_studio as mgr
|
7 |
+
from modelscope_studio.components.Flow import BackgroundPropsDict, Edge, Node
|
8 |
+
|
9 |
+
with open((os.path.join(os.path.dirname(__file__),
|
10 |
+
"../schema/agents_schema.json"))) as f:
|
11 |
+
schema = json.load(f)
|
12 |
+
|
13 |
+
# define the initial value of the flow
|
14 |
+
data = {
|
15 |
+
"nodes": [
|
16 |
+
Node(id="start-node", name="start", position=dict(x=0, y=0)),
|
17 |
+
Node(name="agent",
|
18 |
+
position=dict(x=200, y=0),
|
19 |
+
data=dict(condition=['']))
|
20 |
+
],
|
21 |
+
"edges": [Edge(source='start-node', target="initial-agent-node")],
|
22 |
+
}
|
23 |
+
|
24 |
+
|
25 |
+
def on_data_change(_flow):
|
26 |
+
print(_flow)
|
27 |
+
|
28 |
+
|
29 |
+
flow_props = ["show_sidebar", "show_minimap", "show_controls"]
|
30 |
+
|
31 |
+
|
32 |
+
def on_change(_flow_config, _bgc_variant, _bgc_color, _bgc_gap, _bgc_size,
|
33 |
+
_bgc_offset, _bgc_line_width):
|
34 |
+
new_props = {}
|
35 |
+
new_background_props = {
|
36 |
+
"variant": _bgc_variant,
|
37 |
+
"color": _bgc_color,
|
38 |
+
"gap": _bgc_gap,
|
39 |
+
"size": _bgc_size,
|
40 |
+
"offset": _bgc_offset,
|
41 |
+
'lineWidth': _bgc_line_width
|
42 |
+
}
|
43 |
+
for choice in flow_props:
|
44 |
+
if choice in _flow_config:
|
45 |
+
new_props[choice] = True
|
46 |
+
else:
|
47 |
+
new_props[choice] = False
|
48 |
+
return gr.update(**new_props, background_props=new_background_props)
|
49 |
+
|
50 |
+
|
51 |
+
with gr.Blocks() as demo:
|
52 |
+
with gr.Accordion(label="Flow Options"):
|
53 |
+
flow_config = gr.CheckboxGroup(
|
54 |
+
container=False,
|
55 |
+
value=["show_sidebar", "show_minimap", "show_controls"],
|
56 |
+
choices=flow_props)
|
57 |
+
with gr.Accordion(label="Background Props"):
|
58 |
+
with gr.Row():
|
59 |
+
with gr.Column():
|
60 |
+
bgc_variant = gr.Radio(choices=["dots", "lines", "cross"],
|
61 |
+
label="variant",
|
62 |
+
value="dots")
|
63 |
+
with gr.Column():
|
64 |
+
bgc_color = gr.ColorPicker(label="color", value="")
|
65 |
+
with gr.Column():
|
66 |
+
bgc_gap = gr.Slider(label="gap", value=28)
|
67 |
+
with gr.Column():
|
68 |
+
bgc_size = gr.Slider(label="size",
|
69 |
+
value=1,
|
70 |
+
maximum=10,
|
71 |
+
step=1)
|
72 |
+
with gr.Column():
|
73 |
+
bgc_offset = gr.Slider(label="offset",
|
74 |
+
value=1,
|
75 |
+
step=1,
|
76 |
+
maximum=10)
|
77 |
+
with gr.Column():
|
78 |
+
bgc_line_width = gr.Slider(label="lineWidth",
|
79 |
+
value=1,
|
80 |
+
step=1,
|
81 |
+
maximum=10)
|
82 |
+
|
83 |
+
flow = mgr.Flow(value=data,
|
84 |
+
schema=schema,
|
85 |
+
show_controls=True,
|
86 |
+
show_minimap=True,
|
87 |
+
show_sidebar=True,
|
88 |
+
sync_on_data_change=True,
|
89 |
+
background_props=BackgroundPropsDict(variant='dots'))
|
90 |
+
gr.on(triggers=[
|
91 |
+
flow_config.change, bgc_variant.change, bgc_color.change,
|
92 |
+
bgc_gap.change, bgc_size.change, bgc_offset.change,
|
93 |
+
bgc_line_width.change
|
94 |
+
],
|
95 |
+
fn=on_change,
|
96 |
+
inputs=[
|
97 |
+
flow_config, bgc_variant, bgc_color, bgc_gap, bgc_size,
|
98 |
+
bgc_offset, bgc_line_width
|
99 |
+
],
|
100 |
+
outputs=[flow])
|
101 |
+
flow.data_change(fn=on_data_change, inputs=[flow])
|
102 |
+
|
103 |
+
if __name__ == "__main__":
|
104 |
+
demo.queue().launch()
|
components/Flow/demos/custom_node_type.py
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_studio as mgr
|
4 |
+
from modelscope_studio.components.Flow import (FlowSchemaDict, Node,
|
5 |
+
NodeSchemaAttributeDict,
|
6 |
+
NodeSchemaDict)
|
7 |
+
|
8 |
+
|
9 |
+
def on_data_change(_flow):
|
10 |
+
print(_flow)
|
11 |
+
|
12 |
+
|
13 |
+
def on_custom(data: gr.EventData):
|
14 |
+
print(data._data)
|
15 |
+
|
16 |
+
|
17 |
+
custom_components = {
|
18 |
+
"my-input": {
|
19 |
+
"js":
|
20 |
+
"""
|
21 |
+
(props, cc, { el, theme, onMount, onUpdate }) => {
|
22 |
+
onMount(() => {
|
23 |
+
el.innerHTML = `<input />`
|
24 |
+
const input = el.querySelector('input')
|
25 |
+
input.style.color = theme === 'dark' ? 'white' : 'black'
|
26 |
+
input.style.backgroundColor = theme === 'dark' ? 'black' : 'white'
|
27 |
+
input.addEventListener('change', (e) => {
|
28 |
+
cc.dispatch(e.target.value)
|
29 |
+
})
|
30 |
+
})
|
31 |
+
// props update
|
32 |
+
onUpdate(
|
33 |
+
() => {
|
34 |
+
const input = el.querySelector('input')
|
35 |
+
input.setAttribute('value', props.value || '')
|
36 |
+
},
|
37 |
+
// By default, the callback will not be called when the component is being mounted. Set `callAfterMount` to true to enable it.
|
38 |
+
{ callAfterMount: true }
|
39 |
+
)
|
40 |
+
}
|
41 |
+
"""
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
schema = FlowSchemaDict(nodes=[
|
46 |
+
NodeSchemaDict(name="my-input-node",
|
47 |
+
title="MyInputNode",
|
48 |
+
attrs=[NodeSchemaAttributeDict(name="a", type="my-input")])
|
49 |
+
])
|
50 |
+
|
51 |
+
data = {
|
52 |
+
"nodes": [
|
53 |
+
Node(name="my-input-node",
|
54 |
+
position=dict(x=0, y=0),
|
55 |
+
data=dict(a='Hello'))
|
56 |
+
]
|
57 |
+
}
|
58 |
+
|
59 |
+
with gr.Blocks() as demo:
|
60 |
+
flow = mgr.Flow(value=data,
|
61 |
+
schema=schema,
|
62 |
+
custom_components=custom_components,
|
63 |
+
sync_on_data_change=True)
|
64 |
+
flow.data_change(fn=on_data_change, inputs=[flow])
|
65 |
+
# called when custom component dispatch event
|
66 |
+
flow.custom(fn=on_custom)
|
67 |
+
|
68 |
+
if __name__ == "__main__":
|
69 |
+
demo.queue().launch()
|
components/Flow/schema/agents_schema.json
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"$schema": "https://raw.githubusercontent.com/modelscope/modelscope-studio/main/frontend/Flow/schema.json",
|
3 |
+
"nodes": [
|
4 |
+
{
|
5 |
+
"max": 1,
|
6 |
+
"min": 1,
|
7 |
+
"addable": false,
|
8 |
+
"show_toolbar": false,
|
9 |
+
"name": "start",
|
10 |
+
"title": "Start",
|
11 |
+
"ports": {
|
12 |
+
"source": ["right"],
|
13 |
+
"target": []
|
14 |
+
}
|
15 |
+
},
|
16 |
+
{
|
17 |
+
"icon": "https://img.alicdn.com/imgextra/i4/O1CN01fvt4it25rEZU4Gjso_!!6000000007579-2-tps-128-128.png",
|
18 |
+
"name": "agent",
|
19 |
+
"title": "Agent Node",
|
20 |
+
"description": "Agent Flow Node",
|
21 |
+
"ports": {
|
22 |
+
"target": ["left"],
|
23 |
+
"source": []
|
24 |
+
},
|
25 |
+
"attrs": [
|
26 |
+
{
|
27 |
+
"name": "prompt",
|
28 |
+
"title": "Agent Prompt",
|
29 |
+
"type": "textarea",
|
30 |
+
"required": {
|
31 |
+
"message": "Agent Prompt is required"
|
32 |
+
}
|
33 |
+
},
|
34 |
+
{
|
35 |
+
"name": "tool",
|
36 |
+
"title": "Tools",
|
37 |
+
"type": "select",
|
38 |
+
"props": {
|
39 |
+
"mode": "multiple",
|
40 |
+
"options": [
|
41 |
+
{ "label": "Wanx Image Generation", "value": "image_gen" },
|
42 |
+
{ "label": "Code Interpreter", "value": "code_interpreter" },
|
43 |
+
{ "label": "Web Browsing", "value": "web_browser" }
|
44 |
+
]
|
45 |
+
}
|
46 |
+
},
|
47 |
+
{
|
48 |
+
"name": "condition",
|
49 |
+
"title": "Jump Condition",
|
50 |
+
"list": {
|
51 |
+
"min": 1,
|
52 |
+
"ports": {
|
53 |
+
"source": ["right"]
|
54 |
+
}
|
55 |
+
},
|
56 |
+
"accordion": false
|
57 |
+
}
|
58 |
+
],
|
59 |
+
"template": {
|
60 |
+
"attrs": {
|
61 |
+
"condition": [""]
|
62 |
+
}
|
63 |
+
}
|
64 |
+
}
|
65 |
+
]
|
66 |
+
}
|
components/Flow/schema/agents_schema.py
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
from modelscope_studio.components.Flow import (
|
4 |
+
FlowSchemaDict, NodeSchemaAttributeDict, NodeSchemaAttributeListDict,
|
5 |
+
NodeSchemaAttributeRequiredDict, NodeSchemaDict, NodeSchemaPortsDict,
|
6 |
+
NodeSchemaTemplateDict)
|
7 |
+
|
8 |
+
|
9 |
+
def resolve_assets(relative_path):
|
10 |
+
return os.path.join(os.path.dirname(__file__), "../../resources",
|
11 |
+
relative_path)
|
12 |
+
|
13 |
+
|
14 |
+
schema = FlowSchemaDict(nodes=[
|
15 |
+
NodeSchemaDict(max=1,
|
16 |
+
min=1,
|
17 |
+
addable=False,
|
18 |
+
show_toolbar=False,
|
19 |
+
name="start",
|
20 |
+
title="Start",
|
21 |
+
ports=NodeSchemaPortsDict(source=['right'], target=[])),
|
22 |
+
NodeSchemaDict(
|
23 |
+
icon=resolve_assets('./bot.jpeg'),
|
24 |
+
name="agent",
|
25 |
+
title="Agent Node",
|
26 |
+
description="Agent Flow Node",
|
27 |
+
ports=NodeSchemaPortsDict(source=[], target=['left']),
|
28 |
+
attrs=[
|
29 |
+
NodeSchemaAttributeDict(name="prompt",
|
30 |
+
title="Agent Prompt",
|
31 |
+
type='textarea',
|
32 |
+
required=NodeSchemaAttributeRequiredDict(
|
33 |
+
message="Agent Prompt is required")),
|
34 |
+
NodeSchemaAttributeDict(name="tool",
|
35 |
+
title="Tools",
|
36 |
+
type="select",
|
37 |
+
props={
|
38 |
+
"mode":
|
39 |
+
"multiple",
|
40 |
+
"options": [{
|
41 |
+
"label": "Wanx Image Generation",
|
42 |
+
"value": "image_gen"
|
43 |
+
}, {
|
44 |
+
"label": "Code Interpreter",
|
45 |
+
"value": "code_interpreter"
|
46 |
+
}, {
|
47 |
+
"label": "Web Browsing",
|
48 |
+
"value": "web_browser"
|
49 |
+
}]
|
50 |
+
}),
|
51 |
+
NodeSchemaAttributeDict(
|
52 |
+
name="condition",
|
53 |
+
title="Jump Condition",
|
54 |
+
list=NodeSchemaAttributeListDict(
|
55 |
+
min=1, ports=NodeSchemaPortsDict(source=['right'])),
|
56 |
+
accordion=False)
|
57 |
+
],
|
58 |
+
template=NodeSchemaTemplateDict(attrs=dict(condition=[''])))
|
59 |
+
])
|
components/Markdown/README-zh_CN.md
CHANGED
@@ -55,7 +55,7 @@ custom_select.js
|
|
55 |
</demo-suffix>
|
56 |
</demo>
|
57 |
|
58 |
-
#### 与 Python
|
59 |
|
60 |
在 js 中可以使用`cc.dispatch`触发 Python 侧监听的`custom`事件,以前面的custom_select.js为例,我们在前端调用了`cc.dispatch(options[i])`,则会向 Python 侧同时发送通知。
|
61 |
|
@@ -75,7 +75,7 @@ custom_select.js
|
|
75 |
| preview | bool | True | 是否开启图片预览功能 |
|
76 |
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户定义自定义标签,并通过 js 控制标签渲染样式与触发 python 事件。 |
|
77 |
|
78 |
-
**
|
79 |
|
80 |
```python
|
81 |
class CustomComponentDict(TypedDict):
|
|
|
55 |
</demo-suffix>
|
56 |
</demo>
|
57 |
|
58 |
+
#### 与 Python 交互
|
59 |
|
60 |
在 js 中可以使用`cc.dispatch`触发 Python 侧监听的`custom`事件,以前面的custom_select.js为例,我们在前端调用了`cc.dispatch(options[i])`,则会向 Python 侧同时发送通知。
|
61 |
|
|
|
75 |
| preview | bool | True | 是否开启图片预览功能 |
|
76 |
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户定义自定义标签,并通过 js 控制标签渲染样式与触发 python 事件。 |
|
77 |
|
78 |
+
**CustomComponentDict 定义如下**
|
79 |
|
80 |
```python
|
81 |
class CustomComponentDict(TypedDict):
|
components/Markdown/README.md
CHANGED
@@ -50,7 +50,7 @@ custom_select.js
|
|
50 |
</demo-suffix>
|
51 |
</demo>
|
52 |
|
53 |
-
#### Interaction with Python
|
54 |
|
55 |
In js, you can use `cc.dispatch` to trigger the `custom` event listened to on the Python side. Taking the previous custom_select.js as an example, when we call `cc.dispatch(options[i])` on the frontend, a notification will be sent to the Python side simultaneously.
|
56 |
<demo name="custom-tag4"></demo>
|
@@ -66,8 +66,8 @@ The following APIs are additional extended parameters beyond the original gradio
|
|
66 |
| enable_base64 | bool | False | Whether to support rendering content as base64, since rendering base64 is unsafe, the default is False. |
|
67 |
| preview | bool | True | Whether to enable image preview functionality. |
|
68 |
| enable_latex | bool | True | Whether to enable LaTeX rendering. |
|
69 |
-
| latex_single_dollar_delimiter | bool | True |
|
70 |
-
| custom_components |
|
71 |
| |
|
72 |
|
73 |
**CustomComponent definition is as follows:**
|
|
|
50 |
</demo-suffix>
|
51 |
</demo>
|
52 |
|
53 |
+
#### Interaction with Python
|
54 |
|
55 |
In js, you can use `cc.dispatch` to trigger the `custom` event listened to on the Python side. Taking the previous custom_select.js as an example, when we call `cc.dispatch(options[i])` on the frontend, a notification will be sent to the Python side simultaneously.
|
56 |
<demo name="custom-tag4"></demo>
|
|
|
66 |
| enable_base64 | bool | False | Whether to support rendering content as base64, since rendering base64 is unsafe, the default is False. |
|
67 |
| preview | bool | True | Whether to enable image preview functionality. |
|
68 |
| enable_latex | bool | True | Whether to enable LaTeX rendering. |
|
69 |
+
| latex_single_dollar_delimiter | bool | True | Whe ther to enable single dollar delimiter `$` for LaTeX rendering. |
|
70 |
+
| custom_components | Dict[str, CustomComponentDict] CustomComponentDict definition below | None | Supports user-defined custom tags and controls tag rendering styles and triggers Python events through js. |
|
71 |
| |
|
72 |
|
73 |
**CustomComponent definition is as follows:**
|
components/Markdown/demos/custom-tag2.py
CHANGED
@@ -15,12 +15,29 @@ custom tag:<custom-tag value="aaa"></custom-tag>
|
|
15 |
# The `js` property should be a string containing a JavaScript Function.
|
16 |
"js":
|
17 |
"""
|
18 |
-
(props, cc, { el, onMount }) => {
|
19 |
-
// `onMount` will be called after the template rendered
|
20 |
onMount(() => {
|
21 |
// `el` is the container element
|
22 |
console.log(el)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
console.log(props.children) // By default, `props` will be passed a property named `children`, which can get the content in the tag, such as 'xx' in '<tag>xx</tag>'.
|
25 |
|
26 |
// The return value will be merged with `props` and passed to the template.
|
|
|
15 |
# The `js` property should be a string containing a JavaScript Function.
|
16 |
"js":
|
17 |
"""
|
18 |
+
(props, cc, { el, onMount, onUpdate }) => {
|
19 |
+
// `onMount` will be called after the template first rendered
|
20 |
onMount(() => {
|
21 |
// `el` is the container element
|
22 |
console.log(el)
|
23 |
+
|
24 |
+
// the return function will be called when the component is being unmounted
|
25 |
+
return () => {
|
26 |
+
console.log('unmount')
|
27 |
+
}
|
28 |
+
})
|
29 |
+
|
30 |
+
// `onUpdate` will be called when the props changed
|
31 |
+
onUpdate(() => {
|
32 |
+
console.log(props)
|
33 |
})
|
34 |
+
onUpdate(
|
35 |
+
() => {
|
36 |
+
console.log(props, 'after mount')
|
37 |
+
},
|
38 |
+
// By default, the callback will not be called when the component is being mounted. Set `callAfterMount` to true to enable it.
|
39 |
+
{ callAfterMount: true }
|
40 |
+
)
|
41 |
console.log(props.children) // By default, `props` will be passed a property named `children`, which can get the content in the tag, such as 'xx' in '<tag>xx</tag>'.
|
42 |
|
43 |
// The return value will be merged with `props` and passed to the template.
|
components/MultimodalInput/README.md
CHANGED
@@ -43,7 +43,7 @@ class MultimodalInputData(GradioModel):
|
|
43 |
|
44 |
| Attribute | Type | Default Value | Description |
|
45 |
| ------------------- | ----------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
46 |
-
| sources |
|
47 |
| webcam_props | dict | None | webcam component properties, currently supports passing mirror_webcam(bool), include_audio(bool) |
|
48 |
| upload_button_props | dict | None | Upload file button properties, same as gradio UploadButton |
|
49 |
| submit_button_props | dict | None | Submit button properties, same as gradio Button |
|
|
|
43 |
|
44 |
| Attribute | Type | Default Value | Description |
|
45 |
| ------------------- | ----------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
46 |
+
| sources | List[Literal['upload', 'microphone', 'webcam']] | ['upload'] | A list of types for uploading files. "upload" provides an upload file button. "microphone" supports user audio input. "webcam" supports user photography to generate images or videos. |
|
47 |
| webcam_props | dict | None | webcam component properties, currently supports passing mirror_webcam(bool), include_audio(bool) |
|
48 |
| upload_button_props | dict | None | Upload file button properties, same as gradio UploadButton |
|
49 |
| submit_button_props | dict | None | Submit button properties, same as gradio Button |
|
components/parse_markdown.py
CHANGED
@@ -42,10 +42,16 @@ class MarkdownParser(HTMLParser):
|
|
42 |
return
|
43 |
if tag == "demo":
|
44 |
self.value.append({
|
45 |
-
"type":
|
46 |
-
"
|
47 |
-
"
|
48 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
})
|
50 |
elif tag == "file":
|
51 |
content = self.read_file(dict(attrs)["src"])
|
|
|
42 |
return
|
43 |
if tag == "demo":
|
44 |
self.value.append({
|
45 |
+
"type":
|
46 |
+
"demo",
|
47 |
+
"code_position":
|
48 |
+
dict(attrs).get("code-position", 'left'),
|
49 |
+
"name":
|
50 |
+
dict(attrs)["name"],
|
51 |
+
"prefix":
|
52 |
+
"",
|
53 |
+
"suffix":
|
54 |
+
""
|
55 |
})
|
56 |
elif tag == "file":
|
57 |
content = self.read_file(dict(attrs)["src"])
|
components/resources/custom_components/custom_select.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
(props, cc, { el,
|
2 |
const options = JSON.parse(props.options);
|
3 |
el.innerHTML = `
|
4 |
${options
|
@@ -9,18 +9,21 @@
|
|
9 |
})
|
10 |
.join('')}
|
11 |
`;
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
input
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
});
|
19 |
-
const input = label.getElementsByTagName('input')[0];
|
20 |
-
input.checked = true;
|
21 |
-
// Use cc.dispatch to trigger events.
|
22 |
-
cc.dispatch(options[i]);
|
23 |
});
|
24 |
-
}
|
25 |
-
|
|
|
26 |
};
|
|
|
1 |
+
(props, cc, { el, onUpdate }) => {
|
2 |
const options = JSON.parse(props.options);
|
3 |
el.innerHTML = `
|
4 |
${options
|
|
|
9 |
})
|
10 |
.join('')}
|
11 |
`;
|
12 |
+
onUpdate(
|
13 |
+
() => {
|
14 |
+
const inputs = Array.from(el.getElementsByTagName('input'));
|
15 |
+
Array.from(el.getElementsByTagName('label')).forEach((label, i) => {
|
16 |
+
label.addEventListener('click', () => {
|
17 |
+
inputs.forEach((input) => {
|
18 |
+
input.checked = false;
|
19 |
+
});
|
20 |
+
const input = label.getElementsByTagName('input')[0];
|
21 |
+
input.checked = true;
|
22 |
+
// Use cc.dispatch to trigger events.
|
23 |
+
cc.dispatch(options[i]);
|
24 |
});
|
|
|
|
|
|
|
|
|
25 |
});
|
26 |
+
},
|
27 |
+
{ callAfterMount: true }
|
28 |
+
);
|
29 |
};
|
modelscope_studio-0.1.4-py3-none-any.whl → modelscope_studio-0.2.0-py3-none-any.whl
RENAMED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:26497677e515ca086a7da0719cd3268516f842bab0833ebb00cd33a558b6a1bb
|
3 |
+
size 11001355
|
requirements.txt
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
modelscope_studio
|
2 |
-
modelscope_studio-0.
|
|
|
1 |
modelscope_studio
|
2 |
+
modelscope_studio-0.2.0-py3-none-any.whl
|
src/pyproject.toml
CHANGED
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
8 |
|
9 |
[project]
|
10 |
name = "modelscope_studio"
|
11 |
-
version = "0.1.
|
12 |
description = "A set of extension component, inluding components for conversational input and display in multimodal scenarios, as well as more components for vertical scenarios."
|
13 |
readme = "README.md"
|
14 |
license = "Apache-2.0"
|
@@ -45,10 +45,13 @@ artifacts = [
|
|
45 |
"backend/modelscope_studio/components/Chatbot/templates",
|
46 |
"backend/modelscope_studio/components/MultimodalInput/templates",
|
47 |
"backend/modelscope_studio/components/Markdown/templates",
|
|
|
48 |
]
|
49 |
|
50 |
[tool.hatch.build.targets.sdist]
|
|
|
51 |
include = ["/backend/modelscope_studio"]
|
52 |
|
53 |
[tool.hatch.build.targets.wheel]
|
54 |
packages = ["/backend/modelscope_studio"]
|
|
|
|
8 |
|
9 |
[project]
|
10 |
name = "modelscope_studio"
|
11 |
+
version = "0.1.7"
|
12 |
description = "A set of extension component, inluding components for conversational input and display in multimodal scenarios, as well as more components for vertical scenarios."
|
13 |
readme = "README.md"
|
14 |
license = "Apache-2.0"
|
|
|
45 |
"backend/modelscope_studio/components/Chatbot/templates",
|
46 |
"backend/modelscope_studio/components/MultimodalInput/templates",
|
47 |
"backend/modelscope_studio/components/Markdown/templates",
|
48 |
+
"backend/modelscope_studio/components/WaterfallGallery/templates",
|
49 |
]
|
50 |
|
51 |
[tool.hatch.build.targets.sdist]
|
52 |
+
exclude = ["__pycache__"]
|
53 |
include = ["/backend/modelscope_studio"]
|
54 |
|
55 |
[tool.hatch.build.targets.wheel]
|
56 |
packages = ["/backend/modelscope_studio"]
|
57 |
+
exclude = ["__pycache__"]
|