Spaces:
Running
Running
feat: WebSandbox
Browse files- app.py +9 -0
- components/antd/breadcrumb/demos/basic.py +2 -2
- components/base/application/README-zh_CN.md +35 -0
- components/base/application/README.md +35 -0
- components/base/each/README-zh_CN.md +3 -1
- components/base/each/README.md +3 -1
- components/base/filter/README-zh_CN.md +1 -1
- components/base/filter/README.md +1 -1
- components/base/slot/README-zh_CN.md +1 -1
- components/base/slot/README.md +1 -1
- components/pro/chatbot/README-zh_CN.md +8 -3
- components/pro/chatbot/README.md +7 -2
- components/pro/multimodal_input/README-zh_CN.md +11 -9
- components/pro/multimodal_input/README.md +11 -10
- components/pro/web_sandbox/README-zh_CN.md +64 -0
- components/pro/web_sandbox/README.md +64 -0
- components/pro/web_sandbox/app.py +6 -0
- components/pro/web_sandbox/demos/error_handling.py +28 -0
- components/pro/web_sandbox/demos/html.py +112 -0
- components/pro/web_sandbox/demos/react.py +170 -0
- layout_templates/chatbot/demos/basic.py +4 -0
- layout_templates/chatbot/demos/fine_grained_control.py +1 -0
- requirements.txt +1 -1
- src/pyproject.toml +1 -1
app.py
CHANGED
@@ -149,6 +149,15 @@ pro_menu_items = [{
|
|
149 |
"label": get_text("MultimodalInput", "MultimodalInput 多模态输入框"),
|
150 |
"key": "multimodal_input"
|
151 |
}]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
}]
|
153 |
|
154 |
antd_menu_items = [{
|
|
|
149 |
"label": get_text("MultimodalInput", "MultimodalInput 多模态输入框"),
|
150 |
"key": "multimodal_input"
|
151 |
}]
|
152 |
+
}, {
|
153 |
+
"label":
|
154 |
+
get_text("Interactive Preview", "交互式预览"),
|
155 |
+
"type":
|
156 |
+
"group",
|
157 |
+
"children": [{
|
158 |
+
"label": get_text("WebSandbox", "WebSandbox 网页沙盒"),
|
159 |
+
"key": "web_sandbox"
|
160 |
+
}]
|
161 |
}]
|
162 |
|
163 |
antd_menu_items = [{
|
components/antd/breadcrumb/demos/basic.py
CHANGED
@@ -9,10 +9,10 @@ with gr.Blocks() as demo:
|
|
9 |
antd.Breadcrumb.Item(title="Ant Design")
|
10 |
with antd.Breadcrumb.Item():
|
11 |
with ms.Slot("title"):
|
12 |
-
antd.Button(type="link", href="#")
|
13 |
with antd.Breadcrumb.Item():
|
14 |
with ms.Slot("title"):
|
15 |
-
antd.Button(type="link", href="
|
16 |
with ms.Slot("menu.items"):
|
17 |
with antd.Menu.Item(key="1"):
|
18 |
with ms.Slot("label"):
|
|
|
9 |
antd.Breadcrumb.Item(title="Ant Design")
|
10 |
with antd.Breadcrumb.Item():
|
11 |
with ms.Slot("title"):
|
12 |
+
antd.Button("Link", type="link", href="#")
|
13 |
with antd.Breadcrumb.Item():
|
14 |
with ms.Slot("title"):
|
15 |
+
antd.Button("General", type="link", href="#")
|
16 |
with ms.Slot("menu.items"):
|
17 |
with antd.Menu.Item(key="1"):
|
18 |
with ms.Slot("label"):
|
components/base/application/README-zh_CN.md
CHANGED
@@ -18,3 +18,38 @@
|
|
18 |
<demo name="theme_adaptation" title="根据用户界面主题返回不同权重内容"></demo>
|
19 |
|
20 |
<demo name="custom_event" title="发送自定义事件"></demo>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
<demo name="theme_adaptation" title="根据用户界面主题返回不同权重内容"></demo>
|
19 |
|
20 |
<demo name="custom_event" title="发送自定义事件"></demo>
|
21 |
+
|
22 |
+
## API
|
23 |
+
|
24 |
+
### 属性
|
25 |
+
|
26 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
27 |
+
| ----- | ------------------- | ------ | -------- |
|
28 |
+
| value | ApplicationPageData | None | 页面数据 |
|
29 |
+
|
30 |
+
### 事件
|
31 |
+
|
32 |
+
| 事件 | 描述 |
|
33 |
+
| --------------------------------- | ---------------------------------------------------------------------------- |
|
34 |
+
| `ms.Application.mount(fn, ···)` | 当页面加载时触发。 |
|
35 |
+
| `ms.Application.resize(fn, ···)` | 当页面尺寸变化时触发。 |
|
36 |
+
| `ms.Application.unmount(fn, ···)` | 当页面卸载时触发。 |
|
37 |
+
| `ms.Application.custom(fn, ···)` | 当用户在 JavaScript 中调用`window.ms_globals.dispatch`抛出自定义事件时触发。 |
|
38 |
+
|
39 |
+
### 类型
|
40 |
+
|
41 |
+
```python
|
42 |
+
|
43 |
+
class ApplicationPageScreenData(GradioModel):
|
44 |
+
width: float
|
45 |
+
height: float
|
46 |
+
scrollX: float
|
47 |
+
scrollY: float
|
48 |
+
|
49 |
+
|
50 |
+
class ApplicationPageData(GradioModel):
|
51 |
+
screen: ApplicationPageScreenData
|
52 |
+
language: str
|
53 |
+
theme: str
|
54 |
+
userAgent: str
|
55 |
+
```
|
components/base/application/README.md
CHANGED
@@ -18,3 +18,38 @@ In addition, this component provides the `custom` event, you can send events to
|
|
18 |
<demo name="theme_adaptation" title="Return different weighted content based on user interface theme"></demo>
|
19 |
|
20 |
<demo name="custom_event" title="Send custom events"></demo>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
<demo name="theme_adaptation" title="Return different weighted content based on user interface theme"></demo>
|
19 |
|
20 |
<demo name="custom_event" title="Send custom events"></demo>
|
21 |
+
|
22 |
+
## API
|
23 |
+
|
24 |
+
### Props
|
25 |
+
|
26 |
+
| Attribute | Type | Default Value | Description |
|
27 |
+
| --------- | ------------------- | ------------- | ----------- |
|
28 |
+
| value | ApplicationPageData | None | Page data |
|
29 |
+
|
30 |
+
### 事件
|
31 |
+
|
32 |
+
| Event | Description |
|
33 |
+
| --------------------------------- | --------------------------------------------------------------------------------------------------- |
|
34 |
+
| `ms.Application.mount(fn, ···)` | Triggered when the page is mounted. |
|
35 |
+
| `ms.Application.resize(fn, ···)` | Triggered when the page size changes. |
|
36 |
+
| `ms.Application.unmount(fn, ···)` | Triggered when the page is unmounted. |
|
37 |
+
| `ms.Application.custom(fn, ···)` | Triggered when the user throws a custom event by calling `window.ms_globals.dispatch` in Javascript |
|
38 |
+
|
39 |
+
### Types
|
40 |
+
|
41 |
+
```python
|
42 |
+
|
43 |
+
class ApplicationPageScreenData(GradioModel):
|
44 |
+
width: float
|
45 |
+
height: float
|
46 |
+
scrollX: float
|
47 |
+
scrollY: float
|
48 |
+
|
49 |
+
|
50 |
+
class ApplicationPageData(GradioModel):
|
51 |
+
screen: ApplicationPageScreenData
|
52 |
+
language: str
|
53 |
+
theme: str
|
54 |
+
userAgent: str
|
55 |
+
```
|
components/base/each/README-zh_CN.md
CHANGED
@@ -22,7 +22,9 @@
|
|
22 |
|
23 |
<demo name="use_context_value" title="使用 context_value 参数"></demo>
|
24 |
|
25 |
-
|
|
|
|
|
26 |
|
27 |
| 属性 | 类型 | 默认值 | 描述 |
|
28 |
| ------------- | ---- | ------ | ---------------- |
|
|
|
22 |
|
23 |
<demo name="use_context_value" title="使用 context_value 参数"></demo>
|
24 |
|
25 |
+
## API
|
26 |
+
|
27 |
+
### 属性
|
28 |
|
29 |
| 属性 | 类型 | 默认值 | 描述 |
|
30 |
| ------------- | ---- | ------ | ---------------- |
|
components/base/each/README.md
CHANGED
@@ -21,7 +21,9 @@ If you need to add certain unified properties to all list item components, you c
|
|
21 |
|
22 |
<demo name="use_context_value" title="Using the context_value Parameter"></demo>
|
23 |
|
24 |
-
|
|
|
|
|
25 |
|
26 |
| Attribute | Type | Default Value | Description |
|
27 |
| ------------- | ---- | ------------- | ----------------------------- |
|
|
|
21 |
|
22 |
<demo name="use_context_value" title="Using the context_value Parameter"></demo>
|
23 |
|
24 |
+
## API
|
25 |
+
|
26 |
+
### Props
|
27 |
|
28 |
| Attribute | Type | Default Value | Description |
|
29 |
| ------------- | ---- | ------------- | ----------------------------- |
|
components/base/filter/README-zh_CN.md
CHANGED
@@ -14,7 +14,7 @@
|
|
14 |
<demo name="use_as_item" title="使用 as_item 参数"></demo>
|
15 |
<demo name="use_params_mapping" title="使用 params_mapping 参数"></demo
|
16 |
|
17 |
-
|
18 |
|
19 |
| 属性 | 类型 | 默认值 | 描述 |
|
20 |
| -------------- | ---- | ------ | -------------------------------------------------------------------------------------------- |
|
|
|
14 |
<demo name="use_as_item" title="使用 as_item 参数"></demo>
|
15 |
<demo name="use_params_mapping" title="使用 params_mapping 参数"></demo
|
16 |
|
17 |
+
## API
|
18 |
|
19 |
| 属性 | 类型 | 默认值 | 描述 |
|
20 |
| -------------- | ---- | ------ | -------------------------------------------------------------------------------------------- |
|
components/base/filter/README.md
CHANGED
@@ -14,7 +14,7 @@ If no parameters are provided, this component will block the context transmissio
|
|
14 |
<demo name="use_as_item" title="Using the as_item Parameter"></demo>
|
15 |
<demo name="use_params_mapping" title="Using the params_mapping Parameter"></demo>
|
16 |
|
17 |
-
|
18 |
|
19 |
| Property | Type | Default Value | Description |
|
20 |
| -------------- | ---- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
14 |
<demo name="use_as_item" title="Using the as_item Parameter"></demo>
|
15 |
<demo name="use_params_mapping" title="Using the params_mapping Parameter"></demo>
|
16 |
|
17 |
+
## API
|
18 |
|
19 |
| Property | Type | Default Value | Description |
|
20 |
| -------------- | ---- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
components/base/slot/README-zh_CN.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8 |
|
9 |
<demo name="basic"></demo>
|
10 |
|
11 |
-
|
12 |
|
13 |
| 属性 | 类型 | 默认值 | 描述 |
|
14 |
| -------------- | ---- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
|
|
|
8 |
|
9 |
<demo name="basic"></demo>
|
10 |
|
11 |
+
## API
|
12 |
|
13 |
| 属性 | 类型 | 默认值 | 描述 |
|
14 |
| -------------- | ---- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
|
components/base/slot/README.md
CHANGED
@@ -8,7 +8,7 @@ The slots of components in `modelscope_studio` can be viewed by getting the `SLO
|
|
8 |
|
9 |
<demo name="basic"></demo>
|
10 |
|
11 |
-
|
12 |
|
13 |
| Attribute | Type | Default Value | Description |
|
14 |
| -------------- | ---- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
|
8 |
|
9 |
<demo name="basic"></demo>
|
10 |
|
11 |
+
## API
|
12 |
|
13 |
| Attribute | Type | Default Value | Description |
|
14 |
| -------------- | ---- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
components/pro/chatbot/README-zh_CN.md
CHANGED
@@ -38,9 +38,9 @@
|
|
38 |
|
39 |
<demo name="thinking" position="bottom" collapsible="true"></demo>
|
40 |
|
41 |
-
|
42 |
|
43 |
-
|
44 |
|
45 |
| 属性 | 类型 | 默认值 | 描述 |
|
46 |
| ------------------------------ | ----------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
@@ -56,7 +56,7 @@
|
|
56 |
| max_height | `int \| float \| str \| None` | None | 组件的最大高度,如果传递的是数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
|
57 |
| min_height | `int \| float \| str \| None` | None | 组件的最小高度,如果传递的是数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
|
58 |
|
59 |
-
|
60 |
|
61 |
| 事件 | 描述 |
|
62 |
| -------------------------------------------- | ------------------------------------ |
|
@@ -127,6 +127,11 @@ class ChatbotMarkdownConfig(GradioModel):
|
|
127 |
"right": "$$",
|
128 |
"display": True
|
129 |
},
|
|
|
|
|
|
|
|
|
|
|
130 |
{
|
131 |
"left": "\\(",
|
132 |
"right": "\\)",
|
|
|
38 |
|
39 |
<demo name="thinking" position="bottom" collapsible="true"></demo>
|
40 |
|
41 |
+
## API
|
42 |
|
43 |
+
### 属性
|
44 |
|
45 |
| 属性 | 类型 | 默认值 | 描述 |
|
46 |
| ------------------------------ | ----------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
56 |
| max_height | `int \| float \| str \| None` | None | 组件的最大高度,如果传递的是数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
|
57 |
| min_height | `int \| float \| str \| None` | None | 组件的最小高度,如果传递的是数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
|
58 |
|
59 |
+
### 事件
|
60 |
|
61 |
| 事件 | 描述 |
|
62 |
| -------------------------------------------- | ------------------------------------ |
|
|
|
127 |
"right": "$$",
|
128 |
"display": True
|
129 |
},
|
130 |
+
{
|
131 |
+
"left": "$",
|
132 |
+
"right": "$",
|
133 |
+
"display": False
|
134 |
+
},
|
135 |
{
|
136 |
"left": "\\(",
|
137 |
"right": "\\)",
|
components/pro/chatbot/README.md
CHANGED
@@ -37,7 +37,7 @@ The `message` object includes all configurations from `bot_config` and `user_con
|
|
37 |
|
38 |
<demo name="thinking" position="bottom" collapsible="true"></demo>
|
39 |
|
40 |
-
|
41 |
|
42 |
### Props
|
43 |
|
@@ -55,7 +55,7 @@ The `message` object includes all configurations from `bot_config` and `user_con
|
|
55 |
| max_height | `int \| float \| str \| None` | None | The maximum height of the component, specified in pixels if a number is passed, or in CSS units if a string is passed. |
|
56 |
| min_height | `int \| float \| str \| None` | None | The minimum height of the component, specified in pixels if a number is passed, or in CSS units if a string is passed. |
|
57 |
|
58 |
-
|
59 |
|
60 |
| Event | Description |
|
61 |
| -------------------------------------------- | ------------------------------------------------------- |
|
@@ -126,6 +126,11 @@ class ChatbotMarkdownConfig(GradioModel):
|
|
126 |
"right": "$$",
|
127 |
"display": True
|
128 |
},
|
|
|
|
|
|
|
|
|
|
|
129 |
{
|
130 |
"left": "\\(",
|
131 |
"right": "\\)",
|
|
|
37 |
|
38 |
<demo name="thinking" position="bottom" collapsible="true"></demo>
|
39 |
|
40 |
+
## API
|
41 |
|
42 |
### Props
|
43 |
|
|
|
55 |
| max_height | `int \| float \| str \| None` | None | The maximum height of the component, specified in pixels if a number is passed, or in CSS units if a string is passed. |
|
56 |
| min_height | `int \| float \| str \| None` | None | The minimum height of the component, specified in pixels if a number is passed, or in CSS units if a string is passed. |
|
57 |
|
58 |
+
### Events
|
59 |
|
60 |
| Event | Description |
|
61 |
| -------------------------------------------- | ------------------------------------------------------- |
|
|
|
126 |
"right": "$$",
|
127 |
"display": True
|
128 |
},
|
129 |
+
{
|
130 |
+
"left": "$",
|
131 |
+
"right": "$",
|
132 |
+
"display": False
|
133 |
+
},
|
134 |
{
|
135 |
"left": "\\(",
|
136 |
"right": "\\)",
|
components/pro/multimodal_input/README-zh_CN.md
CHANGED
@@ -24,19 +24,21 @@
|
|
24 |
|
25 |
### 属性
|
26 |
|
27 |
-
| 属性 | 类型
|
28 |
-
| ------------- |
|
29 |
-
| value | `dict \| MultimodalInputValue \| None`
|
30 |
-
| loading | `bool \| None`
|
31 |
-
|
|
32 |
-
|
|
33 |
-
|
|
34 |
-
|
|
|
|
|
|
35 |
|
36 |
### 插槽
|
37 |
|
38 |
```python
|
39 |
-
SLOTS=["prefix"]
|
40 |
```
|
41 |
|
42 |
### 类型
|
|
|
24 |
|
25 |
### 属性
|
26 |
|
27 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
28 |
+
| ------------- | -------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------- |
|
29 |
+
| value | `dict \| MultimodalInputValue \| None` | None | 显示的默认值,格式为`{ "text":"", "files":[] }`。 |
|
30 |
+
| loading | `bool \| None` | None | 输入框是否处处于加载状态,此时可以触发 `cancel` 事件。 |
|
31 |
+
| auto_size | `bool \| { minRows?: number; maxRows?: number } \| None` | { "maxRows": 8 } | 自适应内容高度,可设置为 True \| False 或对象:{ "minRows": 2, "maxRows": 6 }。 |
|
32 |
+
| read_only | `bool \| None` | None | 输入框是否为只读状态。 |
|
33 |
+
| submit_type | `Literal['enter', 'shiftEnter'] \| None` | 'enter' | 输入框触发`submit`事件的方式。 |
|
34 |
+
| placeholder | `str \| None` | None | 输入框的提示信息。 |
|
35 |
+
| disabled | `bool \| None` | None | 是否禁用。 |
|
36 |
+
| upload_config | `MultimodalInputUploadConfig \| dict \| None` | None | 文件上传配置。 |
|
37 |
|
38 |
### 插槽
|
39 |
|
40 |
```python
|
41 |
+
SLOTS=['actions', "prefix", 'footer', 'header']
|
42 |
```
|
43 |
|
44 |
### 类型
|
components/pro/multimodal_input/README.md
CHANGED
@@ -24,19 +24,21 @@ A multimodal input component based on [Ant Design X](https://x.ant.design), supp
|
|
24 |
|
25 |
### Props
|
26 |
|
27 |
-
| Attribute | Type
|
28 |
-
| ------------- |
|
29 |
-
| value | `dict \| MultimodalInputValue \| None`
|
30 |
-
| loading | `bool \| None`
|
31 |
-
|
|
32 |
-
|
|
33 |
-
|
|
34 |
-
|
|
|
|
|
|
35 |
|
36 |
### Slots
|
37 |
|
38 |
```python
|
39 |
-
SLOTS
|
40 |
```
|
41 |
|
42 |
### Types
|
@@ -102,5 +104,4 @@ class MultimodalInputUploadConfig(GradioModel):
|
|
102 |
class MultimodalInputValue(GradioModel):
|
103 |
files: Optional[ListFiles] = None
|
104 |
text: Optional[str] = None
|
105 |
-
|
106 |
```
|
|
|
24 |
|
25 |
### Props
|
26 |
|
27 |
+
| Attribute | Type | Default Value | Description |
|
28 |
+
| ------------- | -------------------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------- |
|
29 |
+
| value | `dict \| MultimodalInputValue \| None` | None | Default value to display, formatted as `{ "text":"", "files":[] }`. |
|
30 |
+
| loading | `bool \| None` | None | Whether the input is in a loading state, in which case the `cancel` event can be triggered. |
|
31 |
+
| auto_size | `bool \| { minRows?: number; maxRows?: number } \| None` | { "maxRows": 8 } | Height auto size feature, can be set to True \| False or an object { "minRows": 2, "maxRows": 6 }. |
|
32 |
+
| read_only | `bool \| None` | None | Whether the input is read-only. |
|
33 |
+
| submit_type | `Literal['enter', 'shiftEnter'] \| None` | 'enter' | How the input box triggers the `submit` event. |
|
34 |
+
| placeholder | `str \| None` | None | Input placeholder text. |
|
35 |
+
| disabled | `bool \| None` | None | Whether to disable. |
|
36 |
+
| upload_config | `MultimodalInputUploadConfig \| dict \| None` | None | File upload configuration. |
|
37 |
|
38 |
### Slots
|
39 |
|
40 |
```python
|
41 |
+
SLOTS=['actions', "prefix", 'footer', 'header']
|
42 |
```
|
43 |
|
44 |
### Types
|
|
|
104 |
class MultimodalInputValue(GradioModel):
|
105 |
files: Optional[ListFiles] = None
|
106 |
text: Optional[str] = None
|
|
|
107 |
```
|
components/pro/web_sandbox/README-zh_CN.md
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# WebSandbox
|
2 |
+
|
3 |
+
前端代码沙箱组件,能够将`React`或`HTML`类型的前端代码在页面编译并预览。
|
4 |
+
|
5 |
+
## 示例
|
6 |
+
|
7 |
+
### 预览 React 代码
|
8 |
+
|
9 |
+
当`template`为`react`时,会自动在`imports`参数中添加以下依赖,当需要特定的某个 React 版本时,可以通过覆盖对应的 key 进行修改:
|
10 |
+
|
11 |
+
```json
|
12 |
+
{
|
13 |
+
"react": "https://esm.sh/react",
|
14 |
+
"react/": "https://esm.sh/react/",
|
15 |
+
"react-dom": "https://esm.sh/react-dom",
|
16 |
+
"react-dom/": "https://esm.sh/react-dom/"
|
17 |
+
}
|
18 |
+
```
|
19 |
+
|
20 |
+
<demo name="react"></demo>
|
21 |
+
|
22 |
+
### 预览 HTML 代码
|
23 |
+
|
24 |
+
<demo name="html"></demo>
|
25 |
+
|
26 |
+
### 处理错误
|
27 |
+
|
28 |
+
<demo name="error_handling"></demo>
|
29 |
+
|
30 |
+
## API
|
31 |
+
|
32 |
+
### 属性
|
33 |
+
|
34 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
35 |
+
| -------------------- | ---------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
36 |
+
| value | `Dict[str, Union[str, SandboxFileData]]` | None | 传入 Sandbox 的文件集合。当`template`为`react`时,`['index.tsx', 'index.jsx', 'index.ts', 'index.js']` 为默认的入口文件,当`template`为`html`时,`['index.html']` 为默认的入口文件。你也可以通过对象的形式填写`is_entry`属性手动指定入口文件。 |
|
37 |
+
| template | `Literal['react', 'html']` | 'react' | Sandbox 渲染的模板类型。 |
|
38 |
+
| show_render_error | `bool` | True | 是否抛出渲染错误提示。 |
|
39 |
+
| show_compile_error | `bool` | True | 是否展示编译失败样式。 |
|
40 |
+
| compile_error_render | `str \| None` | None | 自定义编译失败样式,传入类型为 Javascript 的函数字符串。 |
|
41 |
+
| imports | `Dict[str, str]` | None | 对应 importmap 中的 imports 字段,见 [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap),可用于添加在线的前端依赖模块。 `template` 为 `react` 时会自动添加以下依赖,当需要特定的某个 React 版本时,可以通过覆盖对应的 key 进行修改: `{ "react": "https://esm.sh/react", "react/": "https://esm.sh/react/", "react-dom": "https://esm.sh/react-dom", "react-dom/": "https://esm.sh/react-dom/" }`。 |
|
42 |
+
| height | `str \| float \| int` | 400 | 组件的高度,如果值为数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
|
43 |
+
|
44 |
+
### 事件
|
45 |
+
|
46 |
+
| 事件 | 描述 |
|
47 |
+
| ----------------------------------------- | --------------------------- |
|
48 |
+
| `pro.WebSandbox.compile_success(fn, ···)` | 当 Sandbox 编译成功时触发。 |
|
49 |
+
| `pro.WebSandbox.compile_error(fn, ···)` | 当 Sandbox 编译失败时触发。 |
|
50 |
+
| `pro.WebSandbox.render_error(fn, ···)` | 当 Sandbox 渲染抛错时触发。 |
|
51 |
+
|
52 |
+
### 插槽
|
53 |
+
|
54 |
+
```python
|
55 |
+
SLOTS=['compileErrorRender']
|
56 |
+
```
|
57 |
+
|
58 |
+
### 类型
|
59 |
+
|
60 |
+
```python
|
61 |
+
class SandboxFileData(TypedDict):
|
62 |
+
code: str
|
63 |
+
is_entry: Optional[bool]
|
64 |
+
```
|
components/pro/web_sandbox/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# WebSandbox
|
2 |
+
|
3 |
+
A frontend code sandbox component that compiles and previews `React` or `HTML` code in the page.
|
4 |
+
|
5 |
+
## Examples
|
6 |
+
|
7 |
+
### React Code Preview
|
8 |
+
|
9 |
+
When `template` is set to `react`, the following dependencies will be automatically added to the `imports` parameter. When a specific React version is needed, you can override the corresponding keys:
|
10 |
+
|
11 |
+
```json
|
12 |
+
{
|
13 |
+
"react": "https://esm.sh/react",
|
14 |
+
"react/": "https://esm.sh/react/",
|
15 |
+
"react-dom": "https://esm.sh/react-dom",
|
16 |
+
"react-dom/": "https://esm.sh/react-dom/"
|
17 |
+
}
|
18 |
+
```
|
19 |
+
|
20 |
+
<demo name="react"></demo>
|
21 |
+
|
22 |
+
### HTML Code Preview
|
23 |
+
|
24 |
+
<demo name="html"></demo>
|
25 |
+
|
26 |
+
### Error Handling
|
27 |
+
|
28 |
+
<demo name="error_handling"></demo>
|
29 |
+
|
30 |
+
## API
|
31 |
+
|
32 |
+
### Props
|
33 |
+
|
34 |
+
| Attribute | Type | Default Value | Description |
|
35 |
+
| -------------------- | ---------------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
36 |
+
| value | `Dict[str, Union[str, SandboxFileData]]` | None | Files collection passed to the Sandbox. When `template` is `react`, `['index.tsx', 'index.jsx', 'index.ts', 'index.js']` are the default entry files. When `template` is `html`, `['index.html']` is the default entry file. You can also manually specify the entry file by setting the `is_entry` property. |
|
37 |
+
| template | `Literal['react', 'html']` | 'react' | Template type for Sandbox rendering. |
|
38 |
+
| show_render_error | `bool` | True | Whether to show rendering error messages. |
|
39 |
+
| show_compile_error | `bool` | True | Whether to show compilation failure styles. |
|
40 |
+
| compile_error_render | `str \| None` | None | Custom compilation failure style, passed as a JavaScript function string. |
|
41 |
+
| imports | `Dict[str, str]` | None | Corresponds to the imports field in importmap, see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap), used for adding online frontend dependencies. When `template` is `react`, React-related dependencies are automatically added as shown in the example above. |
|
42 |
+
| height | `str \| float \| int` | 400 | Height of the component. If a number is passed, it's specified in pixels; if a string is passed, it's specified in CSS units. |
|
43 |
+
|
44 |
+
### Events
|
45 |
+
|
46 |
+
| Event | Description |
|
47 |
+
| ----------------------------------------- | ------------------------------------------------- |
|
48 |
+
| `pro.WebSandbox.compile_success(fn, ···)` | Triggered when Sandbox compilation succeeds. |
|
49 |
+
| `pro.WebSandbox.compile_error(fn, ···)` | Triggered when Sandbox compilation fails. |
|
50 |
+
| `pro.WebSandbox.render_error(fn, ···)` | Triggered when Sandbox rendering throws an error. |
|
51 |
+
|
52 |
+
### Slots
|
53 |
+
|
54 |
+
```python
|
55 |
+
SLOTS=['compileErrorRender']
|
56 |
+
```
|
57 |
+
|
58 |
+
### Types
|
59 |
+
|
60 |
+
```python
|
61 |
+
class SandboxFileData(TypedDict):
|
62 |
+
code: str
|
63 |
+
is_entry: Optional[bool]
|
64 |
+
```
|
components/pro/web_sandbox/app.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from helper.Docs import Docs
|
2 |
+
|
3 |
+
docs = Docs(__file__)
|
4 |
+
|
5 |
+
if __name__ == "__main__":
|
6 |
+
docs.render().queue().launch()
|
components/pro/web_sandbox/demos/error_handling.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import modelscope_studio.components.antd as antd
|
3 |
+
import modelscope_studio.components.base as ms
|
4 |
+
import modelscope_studio.components.pro as pro
|
5 |
+
|
6 |
+
with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
|
7 |
+
antd.Divider("Render Error")
|
8 |
+
pro.WebSandbox(value={
|
9 |
+
"index.tsx":
|
10 |
+
"""
|
11 |
+
export default function App() {
|
12 |
+
return <button onClick={() => {
|
13 |
+
throw new Error('Test Error');
|
14 |
+
} }>Click to throw error</button>;
|
15 |
+
}
|
16 |
+
"""
|
17 |
+
},
|
18 |
+
template="react")
|
19 |
+
antd.Divider("Compile Error")
|
20 |
+
pro.WebSandbox(value={}, template="react")
|
21 |
+
antd.Divider("Custom Compile Error Render")
|
22 |
+
with pro.WebSandbox(value={}, template="react"):
|
23 |
+
with ms.Slot("compileErrorRender",
|
24 |
+
params_mapping="(message) => ({ sub_title: message })"):
|
25 |
+
antd.Result(status="error", title="Compile Error")
|
26 |
+
|
27 |
+
if __name__ == "__main__":
|
28 |
+
demo.queue().launch()
|
components/pro/web_sandbox/demos/html.py
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import modelscope_studio.components.antd as antd
|
3 |
+
import modelscope_studio.components.base as ms
|
4 |
+
import modelscope_studio.components.pro as pro
|
5 |
+
|
6 |
+
with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
|
7 |
+
pro.WebSandbox(
|
8 |
+
value={
|
9 |
+
"./index.html":
|
10 |
+
"""<!DOCTYPE html>
|
11 |
+
<html lang="en">
|
12 |
+
<head>
|
13 |
+
<meta charset="UTF-8">
|
14 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
15 |
+
<title>TODO List</title>
|
16 |
+
</head>
|
17 |
+
<body>
|
18 |
+
<div class="todo-container">
|
19 |
+
<h1>TODO List</h1>
|
20 |
+
<input type="text" id="taskInput" placeholder="Add a new task...">
|
21 |
+
<button id="addButton">Add Task</button>
|
22 |
+
<ul id="taskList"></ul>
|
23 |
+
</div>
|
24 |
+
|
25 |
+
<script type="module">
|
26 |
+
import "./index.css";
|
27 |
+
function addTask() {
|
28 |
+
const taskInput = document.getElementById('taskInput');
|
29 |
+
const taskText = taskInput.value.trim();
|
30 |
+
if (taskText === '') return;
|
31 |
+
|
32 |
+
const taskList = document.getElementById('taskList');
|
33 |
+
const li = document.createElement('li');
|
34 |
+
li.textContent = taskText;
|
35 |
+
|
36 |
+
const deleteButton = document.createElement('button');
|
37 |
+
deleteButton.textContent = 'Delete';
|
38 |
+
deleteButton.onclick = function() {
|
39 |
+
taskList.removeChild(li);
|
40 |
+
};
|
41 |
+
|
42 |
+
li.appendChild(deleteButton);
|
43 |
+
taskList.appendChild(li);
|
44 |
+
|
45 |
+
taskInput.value = '';
|
46 |
+
}
|
47 |
+
document.getElementById('addButton').onclick = addTask;
|
48 |
+
</script>
|
49 |
+
</body>
|
50 |
+
</html>""",
|
51 |
+
"./index.css":
|
52 |
+
"""body {
|
53 |
+
font-family: Arial, sans-serif;
|
54 |
+
background-color: #2c3e50;
|
55 |
+
color: #ecf0f1;
|
56 |
+
display: flex;
|
57 |
+
justify-content: center;
|
58 |
+
align-items: center;
|
59 |
+
height: 100vh;
|
60 |
+
margin: 0;
|
61 |
+
}
|
62 |
+
.todo-container {
|
63 |
+
background-color: #34495e;
|
64 |
+
padding: 20px;
|
65 |
+
border-radius: 8px;
|
66 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
67 |
+
width: 300px;
|
68 |
+
}
|
69 |
+
h1 {
|
70 |
+
text-align: center;
|
71 |
+
color: #ecf0f1;
|
72 |
+
}
|
73 |
+
input[type="text"] {
|
74 |
+
width: calc(100% - 22px);
|
75 |
+
padding: 10px;
|
76 |
+
margin-bottom: 10px;
|
77 |
+
border: none;
|
78 |
+
border-radius: 3px;
|
79 |
+
background-color: #ecf0f1;
|
80 |
+
color: #2c3e50;
|
81 |
+
}
|
82 |
+
ul {
|
83 |
+
list-style-type: none;
|
84 |
+
padding: 0;
|
85 |
+
}
|
86 |
+
li {
|
87 |
+
background-color: #2c3e50;
|
88 |
+
margin-bottom: 5px;
|
89 |
+
padding: 10px;
|
90 |
+
border-radius: 3px;
|
91 |
+
display: flex;
|
92 |
+
justify-content: space-between;
|
93 |
+
align-items: center;
|
94 |
+
}
|
95 |
+
button {
|
96 |
+
background-color: #e74c3c;
|
97 |
+
color: #ecf0f1;
|
98 |
+
border: none;
|
99 |
+
padding: 5px 10px;
|
100 |
+
border-radius: 3px;
|
101 |
+
cursor: pointer;
|
102 |
+
}
|
103 |
+
button:hover {
|
104 |
+
background-color: #c0392b;
|
105 |
+
}"""
|
106 |
+
},
|
107 |
+
template="html",
|
108 |
+
height=600,
|
109 |
+
)
|
110 |
+
|
111 |
+
if __name__ == "__main__":
|
112 |
+
demo.queue().launch()
|
components/pro/web_sandbox/demos/react.py
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import modelscope_studio.components.antd as antd
|
3 |
+
import modelscope_studio.components.base as ms
|
4 |
+
import modelscope_studio.components.pro as pro
|
5 |
+
|
6 |
+
with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
|
7 |
+
pro.WebSandbox(value={
|
8 |
+
"./index.tsx":
|
9 |
+
"""import Demo from './demo.tsx'
|
10 |
+
import "@tailwindcss/browser"
|
11 |
+
|
12 |
+
export default Demo
|
13 |
+
""",
|
14 |
+
"./demo.tsx":
|
15 |
+
"""import { useState, useEffect } from 'react';
|
16 |
+
|
17 |
+
export default function App() {
|
18 |
+
const [messages, setMessages] = useState([
|
19 |
+
{ id: 1, sender: 'ai', content: 'Hello! I am your AI assistant. How can I help you today?', timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) },
|
20 |
+
]);
|
21 |
+
const [inputValue, setInputValue] = useState('');
|
22 |
+
const [isTyping, setIsTyping] = useState(false);
|
23 |
+
const [darkMode, setDarkMode] = useState(false);
|
24 |
+
|
25 |
+
// Simulate AI typing effect
|
26 |
+
const handleSendMessage = () => {
|
27 |
+
if (inputValue.trim() === '') return;
|
28 |
+
|
29 |
+
const userMessage = {
|
30 |
+
id: messages.length + 1,
|
31 |
+
sender: 'user',
|
32 |
+
content: inputValue,
|
33 |
+
timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
34 |
+
};
|
35 |
+
|
36 |
+
setMessages((prev) => [...prev, userMessage]);
|
37 |
+
setInputValue('');
|
38 |
+
setIsTyping(true);
|
39 |
+
|
40 |
+
// Simulate AI response after delay
|
41 |
+
setTimeout(() => {
|
42 |
+
const aiResponse = {
|
43 |
+
id: messages.length + 2,
|
44 |
+
sender: 'ai',
|
45 |
+
content: 'I am processing your request and will respond shortly.',
|
46 |
+
timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
47 |
+
};
|
48 |
+
setMessages((prev) => [...prev, aiResponse]);
|
49 |
+
setIsTyping(false);
|
50 |
+
}, 1500);
|
51 |
+
};
|
52 |
+
|
53 |
+
// Handle Enter key press
|
54 |
+
const handleKeyPress = (e) => {
|
55 |
+
if (e.key === 'Enter') {
|
56 |
+
handleSendMessage();
|
57 |
+
}
|
58 |
+
};
|
59 |
+
|
60 |
+
// Toggle dark mode
|
61 |
+
const toggleDarkMode = () => {
|
62 |
+
setDarkMode(!darkMode);
|
63 |
+
};
|
64 |
+
|
65 |
+
useEffect(() => {
|
66 |
+
const app = document.documentElement;
|
67 |
+
if (darkMode) {
|
68 |
+
app.classList.add('dark');
|
69 |
+
} else {
|
70 |
+
app.classList.remove('dark');
|
71 |
+
}
|
72 |
+
}, [darkMode]);
|
73 |
+
|
74 |
+
return (
|
75 |
+
<div className={"min-h-screen flex flex-col transition-colors duration-300 " + (darkMode ? 'bg-gray-900 text-white' : 'bg-gray-100 text-gray-900')}>
|
76 |
+
{/* Header */}
|
77 |
+
<header className={"px-6 py-4 shadow-md flex justify-between items-center " + (darkMode ? 'bg-gray-800' : 'bg-white')}>
|
78 |
+
<div className="flex items-center space-x-2">
|
79 |
+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="text-blue-500">
|
80 |
+
<path d="M12 4L4 8V16L12 20L20 16V8L12 4Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
81 |
+
<path d="M12 15L9 12H15L12 9V15Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
82 |
+
</svg>
|
83 |
+
<h1 className="text-xl font-bold">Chatbot</h1>
|
84 |
+
</div>
|
85 |
+
<button onClick={toggleDarkMode} className="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
86 |
+
{darkMode ? (
|
87 |
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
88 |
+
<circle cx="12" cy="12" r="5" stroke="white" strokeWidth="2"/>
|
89 |
+
<path d="M12 2V4M12 20V22M4 12H2M6.31 6.31L4.9 4.9M17.69 6.31L19.1 4.9M6.31 17.69L4.9 19.1M17.69 17.69L19.1 19.1" stroke="white" strokeWidth="2" strokeLinecap="round"/>
|
90 |
+
</svg>
|
91 |
+
) : (
|
92 |
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
93 |
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
94 |
+
</svg>
|
95 |
+
)}
|
96 |
+
</button>
|
97 |
+
</header>
|
98 |
+
|
99 |
+
{/* Chat Area */}
|
100 |
+
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
101 |
+
{messages.map((message) => (
|
102 |
+
<div
|
103 |
+
key={message.id}
|
104 |
+
className={"flex " + (message.sender === 'user' ? 'justify-end' : 'justify-start')}
|
105 |
+
>
|
106 |
+
<div
|
107 |
+
className={"max-w-xs sm:max-w-md px-4 py-2 rounded-lg " +
|
108 |
+
(message.sender === 'user'
|
109 |
+
? 'bg-blue-500 text-white rounded-br-none'
|
110 |
+
: (darkMode ? 'bg-gray-700' : 'bg-white') + ' rounded-bl-none')
|
111 |
+
}
|
112 |
+
>
|
113 |
+
<p>{message.content}</p>
|
114 |
+
<span className={"text-xs mt-1 block " + (message.sender === 'user' ? 'text-blue-100' : 'text-gray-500')}>
|
115 |
+
{message.timestamp}
|
116 |
+
</span>
|
117 |
+
</div>
|
118 |
+
</div>
|
119 |
+
))}
|
120 |
+
|
121 |
+
{isTyping && (
|
122 |
+
<div className="flex justify-start">
|
123 |
+
<div className={"px-4 py-2 rounded-lg " + (darkMode ? 'bg-gray-700' : 'bg-white') + ' rounded-bl-none'}>
|
124 |
+
<div className="flex space-x-1">
|
125 |
+
<span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }}></span>
|
126 |
+
<span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }}></span>
|
127 |
+
<span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }}></span>
|
128 |
+
</div>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
)}
|
132 |
+
</div>
|
133 |
+
|
134 |
+
{/* Input Area */}
|
135 |
+
<div className={"p-4 border-t " + (darkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200')}>
|
136 |
+
<div className="flex space-x-2">
|
137 |
+
<input
|
138 |
+
type="text"
|
139 |
+
value={inputValue}
|
140 |
+
onChange={(e) => setInputValue(e.target.value)}
|
141 |
+
onKeyPress={handleKeyPress}
|
142 |
+
placeholder="Type a message..."
|
143 |
+
className={"flex-1 px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 " +
|
144 |
+
(darkMode ? 'bg-gray-700 text-white placeholder-gray-400' : 'bg-gray-100 text-gray-900 placeholder-gray-500')
|
145 |
+
}
|
146 |
+
/>
|
147 |
+
<button
|
148 |
+
onClick={handleSendMessage}
|
149 |
+
disabled={inputValue.trim() === ''}
|
150 |
+
className={"px-4 py-2 rounded-lg font-medium text-white bg-blue-500 hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors " +
|
151 |
+
(inputValue.trim() === '' ? 'opacity-50 cursor-not-allowed' : '')
|
152 |
+
}
|
153 |
+
>
|
154 |
+
Send
|
155 |
+
</button>
|
156 |
+
</div>
|
157 |
+
</div>
|
158 |
+
</div>
|
159 |
+
);
|
160 |
+
}"""
|
161 |
+
},
|
162 |
+
height=600,
|
163 |
+
template="react",
|
164 |
+
imports={
|
165 |
+
"@tailwindcss/browser":
|
166 |
+
"https://esm.sh/@tailwindcss/browser",
|
167 |
+
})
|
168 |
+
|
169 |
+
if __name__ == "__main__":
|
170 |
+
demo.queue().launch()
|
layout_templates/chatbot/demos/basic.py
CHANGED
@@ -431,6 +431,9 @@ css = """
|
|
431 |
#chatbot .chatbot-conversations .chatbot-conversations-list {
|
432 |
padding-left: 0;
|
433 |
padding-right: 0;
|
|
|
|
|
|
|
434 |
}
|
435 |
|
436 |
#chatbot .chatbot-chat {
|
@@ -479,6 +482,7 @@ with gr.Blocks(css=css, fill_width=True) as demo:
|
|
479 |
with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
|
480 |
span=0,
|
481 |
order=1,
|
|
|
482 |
elem_classes="chatbot-conversations"):
|
483 |
with antd.Flex(vertical=True,
|
484 |
gap="small",
|
|
|
431 |
#chatbot .chatbot-conversations .chatbot-conversations-list {
|
432 |
padding-left: 0;
|
433 |
padding-right: 0;
|
434 |
+
flex: 1;
|
435 |
+
height: 0;
|
436 |
+
overflow: auto;
|
437 |
}
|
438 |
|
439 |
#chatbot .chatbot-chat {
|
|
|
482 |
with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
|
483 |
span=0,
|
484 |
order=1,
|
485 |
+
elem_style=dict(width=0),
|
486 |
elem_classes="chatbot-conversations"):
|
487 |
with antd.Flex(vertical=True,
|
488 |
gap="small",
|
layout_templates/chatbot/demos/fine_grained_control.py
CHANGED
@@ -541,6 +541,7 @@ with gr.Blocks(css=css, fill_width=True) as demo:
|
|
541 |
with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
|
542 |
span=0,
|
543 |
order=1,
|
|
|
544 |
elem_classes="chatbot-conversations"):
|
545 |
with antd.Flex(vertical=True,
|
546 |
gap="small",
|
|
|
541 |
with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
|
542 |
span=0,
|
543 |
order=1,
|
544 |
+
elem_style=dict(width=0),
|
545 |
elem_classes="chatbot-conversations"):
|
546 |
with antd.Flex(vertical=True,
|
547 |
gap="small",
|
requirements.txt
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
-
modelscope_studio==1.
|
2 |
openai
|
|
|
1 |
+
modelscope_studio==1.3.0
|
2 |
openai
|
src/pyproject.toml
CHANGED
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
8 |
|
9 |
[project]
|
10 |
name = "modelscope_studio"
|
11 |
-
version = "1.
|
12 |
description = "A third-party component library based on Gradio."
|
13 |
readme = "README.md"
|
14 |
license = "Apache-2.0"
|
|
|
8 |
|
9 |
[project]
|
10 |
name = "modelscope_studio"
|
11 |
+
version = "1.3.0"
|
12 |
description = "A third-party component library based on Gradio."
|
13 |
readme = "README.md"
|
14 |
license = "Apache-2.0"
|