Spaces:
Running
Running
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +11 -11
- .gitignore +60 -0
- Dockerfile +16 -0
- README.md +6 -6
- app.py +22 -0
- components/Chatbot/README.md +129 -0
- components/Chatbot/app.py +6 -0
- components/Chatbot/demos/accordion.py +49 -0
- components/Chatbot/demos/basic.py +55 -0
- components/Chatbot/demos/message_config.py +34 -0
- components/Chatbot/demos/multi_bots.py +91 -0
- components/Chatbot/demos/multimodal.py +43 -0
- components/Chatbot/demos/select-box.py +48 -0
- components/Chatbot/resources/audio.wav +0 -0
- components/Chatbot/resources/bot.jpeg +0 -0
- components/Chatbot/resources/custom_components/custom_select.js +26 -0
- components/Chatbot/resources/dog.mp4 +3 -0
- components/Chatbot/resources/image-bot.jpeg +0 -0
- components/Chatbot/resources/music-bot.jpeg +0 -0
- components/Chatbot/resources/screen.jpeg +0 -0
- components/Chatbot/resources/user.jpeg +0 -0
- components/Docs.py +147 -0
- components/Markdown/README.md +87 -0
- components/Markdown/app.py +20 -0
- components/Markdown/custom_tags/accordion.md +23 -0
- components/Markdown/custom_tags/select-box.md +45 -0
- components/Markdown/demos/accordion.py +30 -0
- components/Markdown/demos/basic.py +11 -0
- components/Markdown/demos/custom-tag.py +21 -0
- components/Markdown/demos/custom-tag2.py +38 -0
- components/Markdown/demos/custom-tag3.py +31 -0
- components/Markdown/demos/custom-tag4.py +39 -0
- components/Markdown/demos/custom_tags/accordion/accordion-title.py +19 -0
- components/Markdown/demos/custom_tags/accordion/basic.py +17 -0
- components/Markdown/demos/custom_tags/select-box/basic.py +21 -0
- components/Markdown/demos/custom_tags/select-box/card_shape.py +32 -0
- components/Markdown/demos/custom_tags/select-box/card_shape_width_auto.py +26 -0
- components/Markdown/demos/custom_tags/select-box/python_events.py +23 -0
- components/Markdown/demos/multimodal.py +31 -0
- components/Markdown/demos/select-box.py +32 -0
- components/Markdown/resources/audio.wav +0 -0
- components/Markdown/resources/bot.jpeg +0 -0
- components/Markdown/resources/custom_components/custom_select.js +26 -0
- components/Markdown/resources/dog.mp4 +3 -0
- components/Markdown/resources/screen.jpeg +0 -0
- components/Markdown/resources/user.jpeg +0 -0
- components/MultimodalInput/README.md +50 -0
- components/MultimodalInput/app.py +6 -0
- components/MultimodalInput/demos/basic.py +16 -0
- components/MultimodalInput/demos/config_buttons.py +16 -0
.gitattributes
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
|
|
4 |
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
-
*.
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bin.* filter=lfs diff=lfs merge=lfs -text
|
5 |
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
|
|
6 |
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
|
|
11 |
*.model filter=lfs diff=lfs merge=lfs -text
|
12 |
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
13 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
14 |
*.ot filter=lfs diff=lfs merge=lfs -text
|
15 |
*.parquet filter=lfs diff=lfs merge=lfs -text
|
16 |
*.pb filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
17 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
18 |
*.pth filter=lfs diff=lfs merge=lfs -text
|
19 |
*.rar filter=lfs diff=lfs merge=lfs -text
|
|
|
20 |
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
21 |
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
|
|
22 |
*.tflite filter=lfs diff=lfs merge=lfs -text
|
23 |
*.tgz filter=lfs diff=lfs merge=lfs -text
|
|
|
24 |
*.xz filter=lfs diff=lfs merge=lfs -text
|
25 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
26 |
+
*.zstandard filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.tfevents* filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.db* filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.ark* filter=lfs diff=lfs merge=lfs -text
|
30 |
+
**/*ckpt*data* filter=lfs diff=lfs merge=lfs -text
|
31 |
+
**/*ckpt*.meta filter=lfs diff=lfs merge=lfs -text
|
32 |
+
**/*ckpt*.index filter=lfs diff=lfs merge=lfs -text
|
33 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
34 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -textcomponents/Chatbot/resources/dog.mp4 filter=lfs diff=lfs merge=lfs -text
|
35 |
+
components/Markdown/resources/dog.mp4 filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.eggs/
|
2 |
+
dist/
|
3 |
+
*.pyc
|
4 |
+
__pycache__/
|
5 |
+
*.py[cod]
|
6 |
+
*$py.class
|
7 |
+
__tmp/*
|
8 |
+
*.pyi
|
9 |
+
templates
|
10 |
+
|
11 |
+
# common
|
12 |
+
|
13 |
+
!.*ignore
|
14 |
+
!.*rc
|
15 |
+
!.gitattributes
|
16 |
+
!.aoneci.yml
|
17 |
+
!.editorconfig
|
18 |
+
|
19 |
+
# Logs
|
20 |
+
logs
|
21 |
+
*.log*
|
22 |
+
|
23 |
+
# Runtime data
|
24 |
+
pids
|
25 |
+
*.pid
|
26 |
+
*.seed
|
27 |
+
*.pid.lock
|
28 |
+
|
29 |
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
30 |
+
lib-cov
|
31 |
+
|
32 |
+
# Coverage directory used by tools like istanbul
|
33 |
+
coverage
|
34 |
+
|
35 |
+
# Dependency directories
|
36 |
+
bower_components
|
37 |
+
node_modules/
|
38 |
+
jspm_packages/
|
39 |
+
|
40 |
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
41 |
+
build/Release
|
42 |
+
lib
|
43 |
+
dist
|
44 |
+
|
45 |
+
# TypeScript v1 declaration files
|
46 |
+
typings/
|
47 |
+
|
48 |
+
# Output of 'npm pack'
|
49 |
+
*.tgz
|
50 |
+
|
51 |
+
# xconsole
|
52 |
+
src/.xconsole
|
53 |
+
build
|
54 |
+
.faas_debug_tmp
|
55 |
+
.yarn
|
56 |
+
.yalc
|
57 |
+
yalc.lock
|
58 |
+
.eslintcache
|
59 |
+
.stylelintcache
|
60 |
+
.DS_Store
|
Dockerfile
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
FROM python:3.9
|
3 |
+
|
4 |
+
WORKDIR /code
|
5 |
+
|
6 |
+
COPY --link --chown=1000 . .
|
7 |
+
|
8 |
+
RUN mkdir -p /tmp/cache/
|
9 |
+
RUN chmod a+rwx -R /tmp/cache/
|
10 |
+
ENV TRANSFORMERS_CACHE=/tmp/cache/
|
11 |
+
|
12 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
13 |
+
|
14 |
+
ENV PYTHONUNBUFFERED=1 GRADIO_ALLOW_FLAGGING=never GRADIO_NUM_PORTS=1 GRADIO_SERVER_NAME=0.0.0.0 GRADIO_SERVER_PORT=7860 SYSTEM=spaces
|
15 |
+
|
16 |
+
CMD ["python", "app.py"]
|
README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
|
|
1 |
---
|
2 |
-
|
3 |
-
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
sdk: docker
|
7 |
pinned: false
|
|
|
8 |
---
|
9 |
-
|
10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
+
|
2 |
---
|
3 |
+
tags: [gradio-custom-component]
|
4 |
+
title: modelscope_gradio_components V0.0.1b8
|
5 |
+
colorFrom: red
|
6 |
+
colorTo: red
|
7 |
sdk: docker
|
8 |
pinned: false
|
9 |
+
license: apache-2.0
|
10 |
---
|
|
|
|
app.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
|
7 |
+
readme_docs = Docs(__file__)
|
8 |
+
|
9 |
+
docs = [
|
10 |
+
["开始使用", readme_docs],
|
11 |
+
["Chatbot", chatbot_docs],
|
12 |
+
["Markdown", markdown_docs],
|
13 |
+
["MultimodalInput", multimodel_input_docs],
|
14 |
+
]
|
15 |
+
|
16 |
+
with gr.Blocks() as demo:
|
17 |
+
with gr.Tabs() as components_tabs:
|
18 |
+
for doc in docs:
|
19 |
+
with gr.TabItem(doc[0], id=doc[0]):
|
20 |
+
doc[1].render(components_tabs)
|
21 |
+
|
22 |
+
demo.queue().launch()
|
components/Chatbot/README.md
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Chatbot
|
2 |
+
|
3 |
+
升级版的 gradio Chatbot。
|
4 |
+
|
5 |
+
- 支持前端匀速流式输出 message
|
6 |
+
- 支持输出多模态内容(音频、视频、语音、文件、文本)
|
7 |
+
- 支持多 agent 场景
|
8 |
+
- 支持自定义渲染组件,并与 Python 侧事件交互
|
9 |
+
|
10 |
+
## 如何使用
|
11 |
+
|
12 |
+
### 基本使用
|
13 |
+
|
14 |
+
<demo name="basic"></demo>
|
15 |
+
|
16 |
+
### 多模态 & 支持本地文件的展示
|
17 |
+
|
18 |
+
<demo name="multimodal"></demo>
|
19 |
+
|
20 |
+
### 控制打字机单句 message 开关
|
21 |
+
|
22 |
+
<demo name="message_config"></demo>
|
23 |
+
|
24 |
+
### 支持手风琴内容展示
|
25 |
+
|
26 |
+
在返回的内容中加入 `accordion` 标签,可以在内容中加入手风琴,更多用法详见 <tab-link component-tab="Markdown">Markdown 内置自定义标签</tab-link>
|
27 |
+
|
28 |
+
同时为了适配大模型的工具调用链路,额外对某些大模型的格式做了预设配置,支持下述格式的预设处理(会将下面的格式转换成上方`accordion`标签包裹形式)
|
29 |
+
|
30 |
+
```python
|
31 |
+
import modelscope_gradio_components as mgr
|
32 |
+
from modelscope_gradio_components.components.Chatbot.llm_thinking_presets import qwen
|
33 |
+
|
34 |
+
# 添加 qwen 解析预设
|
35 |
+
mgr.Chatbot(llm_thinking_presets=[qwen()])
|
36 |
+
```
|
37 |
+
|
38 |
+
```text
|
39 |
+
Action: image_gen
|
40 |
+
Action Input: {"text": "风和日丽", "resolution": "1024*1024"}
|
41 |
+
Observation: <result>![IMAGEGEN](https://dashscope-result-sh.oss-cn-shanghai.aliyuncs.com/1d/a2/20231213/723609ee/1926736d-7c6e-4d2f-b438-b7746b3d89f5-1.png?Expires=1702537773&OSSAccessKeyId=LTAI5tQZd8AEcZX6KZV4G8qL&Signature=H%2B0rIn6BMfE%2BOr1uPb7%2Br9G3%2B5w%3D)</result> 根据您的描述"风和日丽",我生成了一张图片。![](https://dashscope-result-sh.oss-cn-shanghai.aliyuncs.com/1d/a2/20231213/723609ee/1926736d-7c6e-4d2f-b438-b7746b3d89f5-1.png?Expires=1702537773&OSSAccessKeyId=LTAI5tQZd8AEcZX6KZV4G8qL&Signature=H%2B0rIn6BMfE%2BOr1uPb7%2Br9G3%2B5w%3D)
|
42 |
+
|
43 |
+
Action: 「任意文本表示,将展示为思考链调用的名称」
|
44 |
+
Action Input: 「任意json or md 内容,将展示到调用过程的下拉框」
|
45 |
+
Observation: <result>「任意 md 内容,将作为完成调用的展示的下拉框内」</result>
|
46 |
+
```
|
47 |
+
|
48 |
+
<demo name="accordion"></demo>
|
49 |
+
|
50 |
+
### 支持用户选择交互
|
51 |
+
|
52 |
+
在返回的内容中加入 `select-box` 标签,更多用法详见 <tab-link component-tab="Markdown">Markdown 内置自定义标签</tab-link>
|
53 |
+
|
54 |
+
<demo name="select-box"></demo>
|
55 |
+
|
56 |
+
### 多 bot 场景
|
57 |
+
|
58 |
+
<demo name="multi_bots"></demo>
|
59 |
+
|
60 |
+
### 自定义标签(高阶用法,需要了解前端知识)
|
61 |
+
|
62 |
+
详见 <tab-link component-tab="Markdown">Markdown</tab-link> 组件
|
63 |
+
|
64 |
+
## API 及参数列表
|
65 |
+
|
66 |
+
以下 API 均为在原有 gradio Chatbot 外的额外拓展参数。
|
67 |
+
|
68 |
+
### value
|
69 |
+
|
70 |
+
接口定义:
|
71 |
+
|
72 |
+
```python
|
73 |
+
|
74 |
+
class FileMessage(GradioModel):
|
75 |
+
file: FileData
|
76 |
+
alt_text: Optional[str] = None
|
77 |
+
|
78 |
+
|
79 |
+
class MultimodalMessage(GradioModel):
|
80 |
+
name: Optional[str] = None
|
81 |
+
text: Optional[str] = None
|
82 |
+
flushing: Optional[bool] = None
|
83 |
+
avatar: Optional[Union[str, FileData]] = ''
|
84 |
+
files: Optional[List[Union[FileMessage, dict, FileData, str]]] = None
|
85 |
+
|
86 |
+
# 支持多 bot 场景
|
87 |
+
MultimodalMessageItem = Optional[Union[MultimodalMessage, MultimodalInputData,
|
88 |
+
dict, str]]
|
89 |
+
|
90 |
+
|
91 |
+
class ChatbotData(GradioRootModel):
|
92 |
+
root: List[Tuple[Union[MultimodalMessageItem, List[MultimodalMessageItem]],
|
93 |
+
Union[MultimodalMessageItem,
|
94 |
+
List[MultimodalMessageItem]]]]
|
95 |
+
```
|
96 |
+
|
97 |
+
### props
|
98 |
+
|
99 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
100 |
+
| -------------------- | -------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
101 |
+
| flushing | bool | True | 是否开启打字机效果。默认只有 bot 的 message 会开启,可以通过单独修改 message 的 flushing 属性精确控制每一条 message 的显示效果 |
|
102 |
+
| enable_base64 | bool | False | 是否支持渲染的内容为 base64,因为直接渲染 base64 有安全问题,默认为 False。 |
|
103 |
+
| preview | bool | True | 是否开启图片预览功能 |
|
104 |
+
| avatar_images | tuple\[str \| Path \| None \| dict \| list, str \| Path \| None \| dict\| list\] | None | 拓展gr.Chatbot的参数值,除了接收 url 外还可以接收 dict 和 list,dict 可以传入avatar和name字段,name字段在渲染时会显示在头像下方。 <br/> - 当传入 dict 时,必须包含有avatar字段。<br/> - 当传入 list 时,一般对应多 bot 模式,每一项可以接收前面所有的值,每个 bot 的头像与 message 中 bot 的位置一一对应 |
|
105 |
+
| avatar_image_align | Literal['top', 'middle', 'bottom'] | 'bottom' | 控制头像与 message 的对齐方式,默认为下对齐 |
|
106 |
+
| avatar_image_width | int | 45 | 头像与名称的宽度 |
|
107 |
+
| flushing_speed | int | 3 | 打字机速度,值为 1 - 10,值越大速度越快 |
|
108 |
+
| llm_thinking_presets | list\[dict\] | \[\] | llm 思考链路解析预设,可以将 llm 调用工具的输出格式转为固定的前端展示格式,需要从modelscope_gradio_components.Chatbot.llm_thinking_presets引入,目前支持:qwen |
|
109 |
+
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户定义自定义标签,并通过 js 控制标签渲染样式与触发 python 事件。 |
|
110 |
+
|
111 |
+
**CustomComponent 定义如下**
|
112 |
+
|
113 |
+
```python
|
114 |
+
class CustomComponentDict(TypedDict):
|
115 |
+
props: Optional[List[str]]
|
116 |
+
template: Optional[str]
|
117 |
+
js: Optional[str]
|
118 |
+
```
|
119 |
+
|
120 |
+
### 内置的自定义标签
|
121 |
+
|
122 |
+
见 <tab-link component-tab="Markdown">Markdown 内置自定义标签</tab-link>
|
123 |
+
|
124 |
+
### event listeners
|
125 |
+
|
126 |
+
| 事件 | 描述 |
|
127 |
+
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
128 |
+
| `mgr.Chatbot.flushed(fn, ···)` | 当打字机效果结束时触发。EventData 为:<br/> - index:当前 message 的 index tuple。<br/> - value:当前 message value。 |
|
129 |
+
| `mgr.Chatbot.custom(fn, ···)` | 自定义标签触发事件时触发,EventData 为:<br/> - index:前 message 的 index tuple。<br/> - tag:当前触发的标签。<br/> - tag_index:当前触发标签的 index,此 index 在 mesage 的 index tuple 基础上重新计算。<br/> - value:自定义传入的值。 |
|
components/Chatbot/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/Chatbot/demos/accordion.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
from modelscope_gradio_components.components.Chatbot.llm_thinking_presets import \
|
7 |
+
qwen
|
8 |
+
|
9 |
+
|
10 |
+
def resolve_assets(relative_path):
|
11 |
+
return os.path.join(os.path.dirname(__file__), "../resources",
|
12 |
+
relative_path)
|
13 |
+
|
14 |
+
|
15 |
+
conversation = [
|
16 |
+
[
|
17 |
+
None, {
|
18 |
+
"text": f"""
|
19 |
+
标签语法:
|
20 |
+
<accordion title="调用 tool">
|
21 |
+
|
22 |
+
```json
|
23 |
+
{{"text": "风和日丽", "resolution": "1024*1024"}}
|
24 |
+
```
|
25 |
+
</accordion>
|
26 |
+
|
27 |
+
qwen preset:
|
28 |
+
Action: image_gen
|
29 |
+
Action Input: {{"text": "风和日丽", "resolution": "1024*1024"}}
|
30 |
+
Observation: <result>![IMAGEGEN]({resolve_assets("screen.jpeg")})</result> 根据您的描述"风和日丽",我生成了一张图片。![]({resolve_assets("screen.jpeg")})
|
31 |
+
|
32 |
+
Action: 「任意文本表示,将展示为思考链调用的名称」
|
33 |
+
Action Input: 「任意json or md 内容,将展示到调用过程的下拉框」
|
34 |
+
Observation: <result>「任意 md 内容,将作为完成调用的展示的下拉框内」</result>
|
35 |
+
""",
|
36 |
+
"flushing": False
|
37 |
+
}
|
38 |
+
],
|
39 |
+
]
|
40 |
+
|
41 |
+
with gr.Blocks() as demo:
|
42 |
+
mgr.Chatbot(
|
43 |
+
value=conversation,
|
44 |
+
llm_thinking_presets=[qwen()],
|
45 |
+
height=600,
|
46 |
+
)
|
47 |
+
|
48 |
+
if __name__ == "__main__":
|
49 |
+
demo.queue().launch()
|
components/Chatbot/demos/basic.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import time
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_gradio_components as mgr
|
7 |
+
|
8 |
+
conversation = [
|
9 |
+
[
|
10 |
+
None,
|
11 |
+
{
|
12 |
+
# bot 第一句话关闭打字机效果,直接输入内容
|
13 |
+
"text": "Hello I'm a chatbot",
|
14 |
+
"flushing": False
|
15 |
+
}
|
16 |
+
],
|
17 |
+
]
|
18 |
+
|
19 |
+
|
20 |
+
def submit(_input, _chatbot):
|
21 |
+
_chatbot.append([_input, None])
|
22 |
+
yield gr.update(interactive=False, value=None), _chatbot
|
23 |
+
time.sleep(2)
|
24 |
+
_chatbot[-1][1] = {"text": _input.text + '!'}
|
25 |
+
yield {
|
26 |
+
chatbot: _chatbot,
|
27 |
+
}
|
28 |
+
|
29 |
+
|
30 |
+
def flushed():
|
31 |
+
return gr.update(interactive=True)
|
32 |
+
|
33 |
+
|
34 |
+
with gr.Blocks() as demo:
|
35 |
+
chatbot = mgr.Chatbot(
|
36 |
+
value=conversation,
|
37 |
+
avatar_images=[
|
38 |
+
os.path.join(os.path.dirname(__file__), "../resources/user.jpeg"),
|
39 |
+
{
|
40 |
+
"name":
|
41 |
+
"bot",
|
42 |
+
"avatar":
|
43 |
+
os.path.join(os.path.dirname(__file__),
|
44 |
+
"../resources/bot.jpeg")
|
45 |
+
}
|
46 |
+
],
|
47 |
+
height=600,
|
48 |
+
)
|
49 |
+
|
50 |
+
input = mgr.MultimodalInput()
|
51 |
+
input.submit(fn=submit, inputs=[input, chatbot], outputs=[input, chatbot])
|
52 |
+
chatbot.flushed(fn=flushed, outputs=[input])
|
53 |
+
|
54 |
+
if __name__ == "__main__":
|
55 |
+
demo.queue().launch()
|
components/Chatbot/demos/message_config.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
|
8 |
+
def submit(_chatbot):
|
9 |
+
_chatbot.append(["test user", "test bot"]) # 此时只有 bot 会开启打字机效果
|
10 |
+
yield _chatbot
|
11 |
+
time.sleep(2)
|
12 |
+
_chatbot.append(["test user", {
|
13 |
+
"text": "test bot",
|
14 |
+
"flushing": False
|
15 |
+
}]) # 两者都没有打字机效果
|
16 |
+
yield _chatbot
|
17 |
+
time.sleep(2)
|
18 |
+
_chatbot.append([{
|
19 |
+
"text": "test user",
|
20 |
+
"flushing": True
|
21 |
+
}, {
|
22 |
+
"text": "test bot",
|
23 |
+
"flushing": False
|
24 |
+
}]) # user 会开启打字机效果
|
25 |
+
yield _chatbot
|
26 |
+
|
27 |
+
|
28 |
+
with gr.Blocks() as demo:
|
29 |
+
chatbot = mgr.Chatbot(height=600, )
|
30 |
+
button = gr.Button("Submit")
|
31 |
+
button.click(fn=submit, inputs=[chatbot], outputs=[chatbot])
|
32 |
+
|
33 |
+
if __name__ == "__main__":
|
34 |
+
demo.queue().launch()
|
components/Chatbot/demos/multi_bots.py
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import time
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_gradio_components as mgr
|
7 |
+
|
8 |
+
|
9 |
+
def resolve_assets(relative_path):
|
10 |
+
return os.path.join(os.path.dirname(__file__), "../resources",
|
11 |
+
relative_path)
|
12 |
+
|
13 |
+
|
14 |
+
conversation = [
|
15 |
+
[
|
16 |
+
None,
|
17 |
+
{
|
18 |
+
# bot 第一句话关闭打字机效果,直接输入内容
|
19 |
+
"text": "Hello I'm a chatbot",
|
20 |
+
"flushing": False
|
21 |
+
}
|
22 |
+
],
|
23 |
+
]
|
24 |
+
|
25 |
+
|
26 |
+
def get_last_bot_message(chatbot):
|
27 |
+
return chatbot[-1][1]
|
28 |
+
|
29 |
+
|
30 |
+
def create_music_bot_message(text: str):
|
31 |
+
return {
|
32 |
+
"text": text,
|
33 |
+
}
|
34 |
+
|
35 |
+
|
36 |
+
def create_image_bot_message(text: str):
|
37 |
+
return {
|
38 |
+
"text": text,
|
39 |
+
}
|
40 |
+
|
41 |
+
|
42 |
+
def submit(_input, _chatbot):
|
43 |
+
_chatbot.append([_input, None])
|
44 |
+
yield gr.update(interactive=False, value=None), _chatbot
|
45 |
+
_chatbot[-1][1] = [
|
46 |
+
"Hello",
|
47 |
+
create_image_bot_message("Hello"),
|
48 |
+
create_music_bot_message("Hello")
|
49 |
+
]
|
50 |
+
|
51 |
+
time.sleep(2)
|
52 |
+
get_last_bot_message(_chatbot)[1][
|
53 |
+
"text"] = f"""Hello, I\'m a image bot\n![image]({resolve_assets("user.jpeg")})"""
|
54 |
+
get_last_bot_message(_chatbot)[2][
|
55 |
+
"text"] = f"""Hello, I\'m a music bot <audio src="{resolve_assets("audio.wav")}"></audio>"""
|
56 |
+
yield {
|
57 |
+
chatbot: _chatbot,
|
58 |
+
}
|
59 |
+
|
60 |
+
|
61 |
+
def flushed():
|
62 |
+
return gr.update(interactive=True)
|
63 |
+
|
64 |
+
|
65 |
+
with gr.Blocks() as demo:
|
66 |
+
chatbot = mgr.Chatbot(
|
67 |
+
value=conversation,
|
68 |
+
avatar_image_width=40,
|
69 |
+
avatar_images=[
|
70 |
+
resolve_assets('user.jpeg'),
|
71 |
+
# default bot avatar and name
|
72 |
+
[{
|
73 |
+
"name": "bot",
|
74 |
+
"avatar": resolve_assets('bot.jpeg')
|
75 |
+
}, {
|
76 |
+
"name": "image bot",
|
77 |
+
"avatar": resolve_assets('image-bot.jpeg')
|
78 |
+
}, {
|
79 |
+
"name": "music bot",
|
80 |
+
"avatar": resolve_assets('music-bot.jpeg')
|
81 |
+
}]
|
82 |
+
],
|
83 |
+
height=600,
|
84 |
+
)
|
85 |
+
|
86 |
+
input = mgr.MultimodalInput()
|
87 |
+
input.submit(fn=submit, inputs=[input, chatbot], outputs=[input, chatbot])
|
88 |
+
chatbot.flushed(fn=flushed, outputs=[input])
|
89 |
+
|
90 |
+
if __name__ == "__main__":
|
91 |
+
demo.queue().launch()
|
components/Chatbot/demos/multimodal.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
|
8 |
+
def resolve_assets(relative_path):
|
9 |
+
return os.path.join(os.path.dirname(__file__), "../resources",
|
10 |
+
relative_path)
|
11 |
+
|
12 |
+
|
13 |
+
conversation = [
|
14 |
+
[
|
15 |
+
None, {
|
16 |
+
"text": f"""
|
17 |
+
图片
|
18 |
+
|
19 |
+
![image]({resolve_assets("bot.jpeg")})
|
20 |
+
|
21 |
+
<img src="{resolve_assets("user.jpeg")}" />
|
22 |
+
|
23 |
+
视频
|
24 |
+
|
25 |
+
<video src="{resolve_assets("dog.mp4")}"></video>
|
26 |
+
|
27 |
+
音频
|
28 |
+
|
29 |
+
<audio src="{resolve_assets("audio.wav")}"></audio>
|
30 |
+
""",
|
31 |
+
"flushing": False
|
32 |
+
}
|
33 |
+
],
|
34 |
+
]
|
35 |
+
|
36 |
+
with gr.Blocks() as demo:
|
37 |
+
mgr.Chatbot(
|
38 |
+
value=conversation,
|
39 |
+
height=600,
|
40 |
+
)
|
41 |
+
|
42 |
+
if __name__ == "__main__":
|
43 |
+
demo.queue().launch()
|
components/Chatbot/demos/select-box.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
# label 为对用户展示值,value 为实际选择值
|
8 |
+
options = [{"label": "A", "value": "a"}, "b", "c"]
|
9 |
+
|
10 |
+
conversation = [[
|
11 |
+
None, f"""
|
12 |
+
Single Select: <select-box options='{json.dumps(options)}' select-once></select-box>
|
13 |
+
|
14 |
+
Multiple Select:<select-box type="checkbox" options='{json.dumps(options)}' select-once submit-text="Submit"></select-box>
|
15 |
+
|
16 |
+
Vertical Direction:
|
17 |
+
|
18 |
+
<select-box direction="vertical" type="checkbox" options='{json.dumps(options)}' select-once submit-text="Submit"></select-box>
|
19 |
+
|
20 |
+
Card Shape:
|
21 |
+
|
22 |
+
<select-box shape="card" options='{json.dumps(options)}' select-once equal-height></select-box>
|
23 |
+
|
24 |
+
|
25 |
+
<select-box shape="card" columns="2" options='{json.dumps(options)}' select-once equal-height></select-box>
|
26 |
+
|
27 |
+
|
28 |
+
<select-box shape="card" direction="vertical" options='{json.dumps(options)}' select-once equal-height></select-box>
|
29 |
+
"""
|
30 |
+
]]
|
31 |
+
|
32 |
+
|
33 |
+
# 必须使用 gr.EventData 显示标注
|
34 |
+
def fn(data: gr.EventData):
|
35 |
+
print(data._data)
|
36 |
+
|
37 |
+
|
38 |
+
with gr.Blocks() as demo:
|
39 |
+
chatbot = mgr.Chatbot(
|
40 |
+
value=conversation,
|
41 |
+
flushing=False,
|
42 |
+
height=600,
|
43 |
+
)
|
44 |
+
# 所有自定义标签都会触发 custom 事件
|
45 |
+
chatbot.custom(fn=fn)
|
46 |
+
|
47 |
+
if __name__ == "__main__":
|
48 |
+
demo.queue().launch()
|
components/Chatbot/resources/audio.wav
ADDED
Binary file (44.8 kB). View file
|
|
components/Chatbot/resources/bot.jpeg
ADDED
components/Chatbot/resources/custom_components/custom_select.js
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(props, cc, { el, onMount }) => {
|
2 |
+
const options = JSON.parse(props.options);
|
3 |
+
el.innerHTML = `
|
4 |
+
${options
|
5 |
+
.map((option) => {
|
6 |
+
return `<div>
|
7 |
+
<label>${option} <input type="radio"/></label>
|
8 |
+
<div>`;
|
9 |
+
})
|
10 |
+
.join('')}
|
11 |
+
`;
|
12 |
+
onMount(() => {
|
13 |
+
const inputs = Array.from(el.getElementsByTagName('input'));
|
14 |
+
Array.from(el.getElementsByTagName('label')).forEach((label, i) => {
|
15 |
+
label.addEventListener('click', () => {
|
16 |
+
inputs.forEach((input) => {
|
17 |
+
input.checked = false;
|
18 |
+
});
|
19 |
+
const input = label.getElementsByTagName('input')[0];
|
20 |
+
input.checked = true;
|
21 |
+
// 通过 cc.dispatch 向 python 侧发送通知
|
22 |
+
cc.dispatch(options[i]);
|
23 |
+
});
|
24 |
+
});
|
25 |
+
});
|
26 |
+
};
|
components/Chatbot/resources/dog.mp4
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:39d086ce29e48cf76e5042d2f3f0611ee46575f70fa3dc0c40dd4cfffde3d933
|
3 |
+
size 8626383
|
components/Chatbot/resources/image-bot.jpeg
ADDED
components/Chatbot/resources/music-bot.jpeg
ADDED
components/Chatbot/resources/screen.jpeg
ADDED
components/Chatbot/resources/user.jpeg
ADDED
components/Docs.py
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import re
|
3 |
+
from typing import Callable
|
4 |
+
|
5 |
+
import gradio as gr
|
6 |
+
|
7 |
+
import modelscope_gradio_components as mgr
|
8 |
+
|
9 |
+
from .parse_markdown import parse_markdown
|
10 |
+
|
11 |
+
with open(os.path.join(os.path.dirname(__file__), "tab-link.js")) as f:
|
12 |
+
tab_link_js = f.read()
|
13 |
+
|
14 |
+
custom_components = {
|
15 |
+
"tab-link": {
|
16 |
+
"props": ["tab", "component-tab"],
|
17 |
+
"js": tab_link_js
|
18 |
+
}
|
19 |
+
}
|
20 |
+
|
21 |
+
|
22 |
+
def remove_formatter(markdown_text):
|
23 |
+
pattern = r"^---[\s\S]*?---"
|
24 |
+
|
25 |
+
replaced_text = re.sub(pattern, "", markdown_text)
|
26 |
+
|
27 |
+
return replaced_text
|
28 |
+
|
29 |
+
|
30 |
+
def list_demos(dir_path: str, prefix=''):
|
31 |
+
result = []
|
32 |
+
if (not os.path.isdir(dir_path)):
|
33 |
+
return result
|
34 |
+
for name in os.listdir(dir_path):
|
35 |
+
path = os.path.join(dir_path, name)
|
36 |
+
|
37 |
+
if os.path.isfile(path):
|
38 |
+
result.append(prefix + name)
|
39 |
+
elif os.path.isdir(path):
|
40 |
+
sub_prefix = prefix + name + '/'
|
41 |
+
result.extend(list_demos(path, sub_prefix))
|
42 |
+
|
43 |
+
return result
|
44 |
+
|
45 |
+
|
46 |
+
def get_demo_modules(file_path: str):
|
47 |
+
import importlib.util
|
48 |
+
|
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:
|
56 |
+
demo_name = demo.split(".")[0]
|
57 |
+
spec = importlib.util.spec_from_file_location(
|
58 |
+
"demo", os.path.join(os.path.dirname(file_path), "demos", demo))
|
59 |
+
module = importlib.util.module_from_spec(spec)
|
60 |
+
spec.loader.exec_module(module)
|
61 |
+
demo_modules[demo_name] = module
|
62 |
+
return demo_modules
|
63 |
+
|
64 |
+
|
65 |
+
class Docs:
|
66 |
+
|
67 |
+
def __init__(self, file_path: str, markdown_files: list = None):
|
68 |
+
self.file_path = file_path
|
69 |
+
self.demo_modules = get_demo_modules(file_path)
|
70 |
+
# default current directory
|
71 |
+
self.markdown_files = markdown_files if markdown_files else [
|
72 |
+
file_name for file_name in os.listdir(os.path.dirname(file_path))
|
73 |
+
if file_name.endswith(".md")
|
74 |
+
]
|
75 |
+
self.tabs = None
|
76 |
+
|
77 |
+
def read_file(self, relative_path: str):
|
78 |
+
with open(os.path.join(os.path.dirname(self.file_path), relative_path),
|
79 |
+
"r") as f:
|
80 |
+
return f.read()
|
81 |
+
|
82 |
+
def render_demo(self, demo_name, prefix='', suffix=''):
|
83 |
+
content = self.read_file(f"./demos/{demo_name}.py")
|
84 |
+
module = self.demo_modules[demo_name]
|
85 |
+
with gr.Accordion("Show Demo", open=False):
|
86 |
+
with gr.Row():
|
87 |
+
with gr.Column():
|
88 |
+
mgr.Markdown(f"""
|
89 |
+
{prefix}
|
90 |
+
````python
|
91 |
+
{content}
|
92 |
+
````
|
93 |
+
{suffix}
|
94 |
+
""",
|
95 |
+
header_links=True,
|
96 |
+
custom_components=custom_components)
|
97 |
+
with gr.Column():
|
98 |
+
module.demo.render()
|
99 |
+
|
100 |
+
def render_markdown(self,
|
101 |
+
markdown_file,
|
102 |
+
on_tab_link_click: Callable = None,
|
103 |
+
components_tabs=None):
|
104 |
+
items = parse_markdown(remove_formatter(self.read_file(markdown_file)),
|
105 |
+
read_file=self.read_file)
|
106 |
+
for item in items:
|
107 |
+
if item["type"] == "text":
|
108 |
+
md = mgr.Markdown(item["value"],
|
109 |
+
header_links=True,
|
110 |
+
custom_components=custom_components)
|
111 |
+
# 过滤
|
112 |
+
deps = [dep for dep in [components_tabs, self.tabs] if dep]
|
113 |
+
if len(deps) > 0:
|
114 |
+
md.custom(fn=on_tab_link_click, outputs=deps)
|
115 |
+
elif item["type"] == "demo":
|
116 |
+
self.render_demo(item["name"],
|
117 |
+
prefix=item["prefix"],
|
118 |
+
suffix=item["suffix"])
|
119 |
+
|
120 |
+
def render(self, components_tabs=None):
|
121 |
+
|
122 |
+
def tab_link_click(data: gr.EventData):
|
123 |
+
tab: str = data._data["value"].get("tab", '')
|
124 |
+
component_tab: str = data._data["value"].get("component_tab", '')
|
125 |
+
if tab and tabs:
|
126 |
+
return {tabs: gr.update(selected=tab)}
|
127 |
+
elif components_tabs and component_tab:
|
128 |
+
return {components_tabs: gr.update(selected=component_tab)}
|
129 |
+
|
130 |
+
with gr.Blocks() as demo:
|
131 |
+
|
132 |
+
if len(self.markdown_files) > 1:
|
133 |
+
with gr.Tabs() as tabs:
|
134 |
+
self.tabs = tabs
|
135 |
+
|
136 |
+
for markdown_file in self.markdown_files:
|
137 |
+
tab_name = ".".join(markdown_file.split(".")[:-1])
|
138 |
+
with gr.TabItem(tab_name, id=tab_name):
|
139 |
+
self.render_markdown(
|
140 |
+
markdown_file,
|
141 |
+
on_tab_link_click=tab_link_click,
|
142 |
+
components_tabs=components_tabs)
|
143 |
+
else:
|
144 |
+
self.render_markdown(self.markdown_files[0],
|
145 |
+
on_tab_link_click=tab_link_click,
|
146 |
+
components_tabs=components_tabs)
|
147 |
+
return demo
|
components/Markdown/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Markdown
|
2 |
+
|
3 |
+
升级版的 gradio Markdown。
|
4 |
+
|
5 |
+
- 支持输出多模态内容(音频、视频、语音、文件、文本)
|
6 |
+
- 支持自定义渲染组件,并与 Python 侧事件交互
|
7 |
+
|
8 |
+
## 如何使用
|
9 |
+
|
10 |
+
### 基本使用
|
11 |
+
|
12 |
+
<demo name="basic"></demo>
|
13 |
+
|
14 |
+
### 多模态 & 支持本地文件的展示
|
15 |
+
|
16 |
+
<demo name="multimodal"></demo>
|
17 |
+
|
18 |
+
### 支持手风琴内容展示
|
19 |
+
|
20 |
+
在返回的内容中加入 `accordion` 标签,更多用法详见 <tab-link tab="custom_tags/accordion">accordion</tab-link>
|
21 |
+
|
22 |
+
<demo name="accordion"></demo>
|
23 |
+
|
24 |
+
### 支持用户选择交互
|
25 |
+
|
26 |
+
在返回的内容中加入 `select-box` 标签,更多用法详见 <tab-link tab="custom_tags/select-box">select-box</tab-link>
|
27 |
+
|
28 |
+
<demo name="select-box"></demo>
|
29 |
+
|
30 |
+
### 自定义标签(高阶用法,需要了解前端知识)
|
31 |
+
|
32 |
+
<demo name="custom-tag"></demo>
|
33 |
+
|
34 |
+
#### 引入 js
|
35 |
+
|
36 |
+
<demo name="custom-tag2"></demo>
|
37 |
+
|
38 |
+
template只能做简单的变量替换,如果想要引入更多自定义的行为,如条件判断、循环渲染等,请使用 js 控制 el 自行处理,下面是简单的示例:
|
39 |
+
|
40 |
+
<demo name="custom-tag3">
|
41 |
+
<demo-suffix>
|
42 |
+
custom_select.js
|
43 |
+
|
44 |
+
```js
|
45 |
+
<file src="./resources/custom_components/custom_select.js"></file>
|
46 |
+
```
|
47 |
+
|
48 |
+
</demo-suffix>
|
49 |
+
</demo>
|
50 |
+
|
51 |
+
#### 与 Python 侧交互
|
52 |
+
|
53 |
+
在 js 中可以使用`cc.dispatch`触发 Python 侧监听的`custom`事件,以前面的custom_select.js为例,我们在前端调用了`cc.dispatch(options[i])`,则会向 Python 侧同时发送通知。
|
54 |
+
|
55 |
+
<demo name="custom-tag4"></demo>
|
56 |
+
|
57 |
+
## API 及参数列表
|
58 |
+
|
59 |
+
以下 API 均为在原有 gradio Markdown 外的额外拓展参数。
|
60 |
+
|
61 |
+
### props
|
62 |
+
|
63 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
64 |
+
| ----------------- | --------------------------------------------------------------- | ------ | --------------------------------------------------------------------------- |
|
65 |
+
| enable_base64 | bool | False | 是否支持渲染的内容为 base64,因为直接渲染 base64 有安全问题,默认为 False。 |
|
66 |
+
| preview | bool | True | 是否开启图片预览功能 |
|
67 |
+
| custom_components | dict\[str, CustomComponentDict\] CustomComponentDict 定义见下方 | None | 支持用户定义自定义标签,并通过 js 控制标签渲染样式与触发 python 事件。 |
|
68 |
+
|
69 |
+
**CustomComponent 定义如下**
|
70 |
+
|
71 |
+
```python
|
72 |
+
class CustomComponentDict(TypedDict):
|
73 |
+
props: Optional[List[str]]
|
74 |
+
template: Optional[str]
|
75 |
+
js: Optional[str]
|
76 |
+
```
|
77 |
+
|
78 |
+
### 内置的自定义标签
|
79 |
+
|
80 |
+
- <tab-link tab="custom_tags/select-box">select-box</tab-link>
|
81 |
+
- <tab-link tab="custom_tags/accordion">accordion</tab-link>
|
82 |
+
|
83 |
+
### event listeners
|
84 |
+
|
85 |
+
| 事件 | 描述 |
|
86 |
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
87 |
+
| `mgr.Markdown.custom(fn, ···)` | 自定义标签触发事件时触发,EventData 为:<br/> - index:当前 message 的 index tuple ([message index, user group(index 0) or bot group(index 1), user/bot group index])。<br/> - tag:当前触发的标签。<br/> - tag_index:当前触发标签的 index,此 index 在 mesage 的 index tuple 基础上重新计算。<br/> - value:自定义传入的值。 |
|
components/Markdown/app.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
from components.Docs import Docs
|
4 |
+
|
5 |
+
|
6 |
+
def resolve(relative_path: str):
|
7 |
+
return os.path.join(os.path.dirname(__file__), relative_path)
|
8 |
+
|
9 |
+
|
10 |
+
docs = Docs(
|
11 |
+
__file__,
|
12 |
+
markdown_files=(["README.md"] + [
|
13 |
+
f"custom_tags/{file_name}"
|
14 |
+
for file_name in os.listdir(resolve('custom_tags'))
|
15 |
+
if file_name.endswith(".md")
|
16 |
+
]),
|
17 |
+
)
|
18 |
+
|
19 |
+
if __name__ == "__main__":
|
20 |
+
docs.render().queue().launch()
|
components/Markdown/custom_tags/accordion.md
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# accordion
|
2 |
+
|
3 |
+
在 markdown 文本中添加手风琴效果。
|
4 |
+
|
5 |
+
## 如何使用
|
6 |
+
|
7 |
+
### 基本使用
|
8 |
+
|
9 |
+
<demo name="custom_tags/accordion/basic"></demo>
|
10 |
+
|
11 |
+
### 使用 accordion-title 标记
|
12 |
+
|
13 |
+
使用`::accordion-title[content]`的形式可以在标题输入 markdown 文本。
|
14 |
+
|
15 |
+
<demo name="custom_tags/accordion/accordion-title"></demo>
|
16 |
+
|
17 |
+
## API 及参数列表
|
18 |
+
|
19 |
+
### props
|
20 |
+
|
21 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
22 |
+
| ----- | ------ | ------ | ------------ |
|
23 |
+
| title | string | | 手风琴的标题 |
|
components/Markdown/custom_tags/select-box.md
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# select-box
|
2 |
+
|
3 |
+
在 markdown 文本中添加选择交互框。
|
4 |
+
|
5 |
+
## 如何使用
|
6 |
+
|
7 |
+
### 基本使用
|
8 |
+
|
9 |
+
<demo name="custom_tags/select-box/basic"></demo>
|
10 |
+
|
11 |
+
### Card 样式
|
12 |
+
|
13 |
+
<demo name="custom_tags/select-box/card_shape"></demo>
|
14 |
+
|
15 |
+
### Card 自适应内部元素宽度
|
16 |
+
|
17 |
+
<demo name="custom_tags/select-box/card_shape_width_auto"></demo>
|
18 |
+
|
19 |
+
### 监听 Python 事件
|
20 |
+
|
21 |
+
<demo name="custom_tags/select-box/python_events"></demo>
|
22 |
+
|
23 |
+
## API 及参数列表
|
24 |
+
|
25 |
+
### value
|
26 |
+
|
27 |
+
custom 事件中 custom_data value 对应值, 返回值为用户 options 传入的对应 value ,如果type="checkbox",则返回一个 list。
|
28 |
+
|
29 |
+
### props
|
30 |
+
|
31 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
32 |
+
| ------------ | ------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
33 |
+
| type | 'checkbox' \| 'radio' | 'radio' | 选择框类型,'radio' 为单选框、'checkbox'为多选框。 |
|
34 |
+
| disabled | boolean | | 禁用选择,通常在需要读取历史信息二次渲染时会用到。 |
|
35 |
+
| value | string | | 默认选中值,通常适用于`type="checkbox"`时提前为用户选择部分选项和设置`disabled`后的默认值渲染。 |
|
36 |
+
| direction | 'horizontal' \| 'vertical' | 'horizontal' | 横向或竖向排列选择框 |
|
37 |
+
| shape | 'card' \| 'default' | 'default' | 选择框样式 |
|
38 |
+
| options | (string\| { label?: string, value?: string, imgSrc?: string})\[\] | | 为用户提供的选项值,每一项可以为 string 或 object。 当值为 object 时可以接收更多自定义值,其中imgSrc只有当shape="card"时才生效。 |
|
39 |
+
| select-once | boolean | false | 是否只允许用户选择一次 |
|
40 |
+
| submit-text | string | | 提交按钮的展示值,当该属性有值时,会展示提交按钮,此时用户只有点击提交按钮后才会触发选择事件。 |
|
41 |
+
| columns | number \| { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | { xs: 1, sm: 2, md: 2, lg: 4} | 当shape="card"时才生效。每一行选项占用列数,值的范围为1 - 24,建议此项取值可以被 24 整除,否则可能列数会不符合预期。 当此项传入值为对象时,可以响应式控制每一行渲染列数,响应阈值如下:<br/> - xs:屏幕 < 576px <br/> - sm:屏幕 ≥ 576px <br/> - md:屏幕 ≥ 768px <br/> - lg:屏幕 ≥ 992px <br/> - xl:屏幕 ≥ 1200px <br/> - xxl:屏幕 ≥ 1600px 当direction为vertical时此配置不生效。 |
|
42 |
+
| item-width | string | | 当shape="card"时才生效。每个选项的宽度,如:'auto'、'100px',默认使用 columns 自动分配的宽度。 |
|
43 |
+
| item-height | string | | 当shape="card"时才生效。每个选项的高度,默认自适应元素高度。 |
|
44 |
+
| img-height | string | '160px' | 当shape="card"时才生效。每个选项中图片的高度。 |
|
45 |
+
| equal-height | boolean | false | 当shape="card"时才生效。是否每一行的选项高度都相等,会使用高度最高的选项。 |
|
components/Markdown/demos/accordion.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
with gr.Blocks() as demo:
|
6 |
+
mgr.Markdown(f"""
|
7 |
+
普通调用:
|
8 |
+
|
9 |
+
<accordion title="调用 tool">
|
10 |
+
|
11 |
+
```json
|
12 |
+
{{"text": "风和日丽", "resolution": "1024*1024"}}
|
13 |
+
```
|
14 |
+
|
15 |
+
</accordion>
|
16 |
+
|
17 |
+
使用 ::accordion-title 标记支持 markdown 语法:
|
18 |
+
|
19 |
+
<accordion>
|
20 |
+
|
21 |
+
::accordion-title[调用 `tool`]
|
22 |
+
|
23 |
+
```json
|
24 |
+
{{"text": "风和日丽", "resolution": "1024*1024"}}
|
25 |
+
```
|
26 |
+
</accordion>
|
27 |
+
""")
|
28 |
+
|
29 |
+
if __name__ == "__main__":
|
30 |
+
demo.queue().launch()
|
components/Markdown/demos/basic.py
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
with gr.Blocks() as demo:
|
6 |
+
mgr.Markdown(
|
7 |
+
"This _example_ was **written** in [Markdown](https://en.wikipedia.org/wiki/Markdown)\n"
|
8 |
+
)
|
9 |
+
|
10 |
+
if __name__ == "__main__":
|
11 |
+
demo.queue().launch()
|
components/Markdown/demos/custom-tag.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
with gr.Blocks() as demo:
|
6 |
+
mgr.Markdown(
|
7 |
+
f"""
|
8 |
+
custom tag:<custom-tag value="aaa"></custom-tag>
|
9 |
+
""",
|
10 |
+
custom_components={
|
11 |
+
# key 为标签名
|
12 |
+
"custom-tag": {
|
13 |
+
# 自定义标签允许接收的值,可在调用标签时由用户传入
|
14 |
+
"props": ["value"],
|
15 |
+
# 实际渲染时的 template, 可以使用 {} 将用户传入的 props 替换。
|
16 |
+
"template": "<div>{value}</div>"
|
17 |
+
}
|
18 |
+
})
|
19 |
+
|
20 |
+
if __name__ == "__main__":
|
21 |
+
demo.queue().launch()
|
components/Markdown/demos/custom-tag2.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
with gr.Blocks() as demo:
|
6 |
+
mgr.Markdown(
|
7 |
+
f"""
|
8 |
+
custom tag:<custom-tag value="aaa"></custom-tag>
|
9 |
+
""",
|
10 |
+
custom_components={
|
11 |
+
# key 为标签名
|
12 |
+
"custom-tag": {
|
13 |
+
"props": ["value"],
|
14 |
+
"template":
|
15 |
+
"<button onclick='{onClick}'>{value}</button>",
|
16 |
+
# js 接收一个 function
|
17 |
+
"js":
|
18 |
+
"""
|
19 |
+
(props, cc, { el, onMount }) => {
|
20 |
+
// onMount 会在 template 渲染完成后调用
|
21 |
+
onMount(() => {
|
22 |
+
// el 是当前自定义标签挂载的 container
|
23 |
+
console.log(el)
|
24 |
+
})
|
25 |
+
console.log(props.children) // 默认会包含 children,可以拿到 <tag>xx</tag> 标签内的内容 xx
|
26 |
+
// 可以返回一个对象,对象里的值会与 props 做并集最后渲染到模板中
|
27 |
+
return {
|
28 |
+
value: 'Click Me: ' + props.value,
|
29 |
+
onClick: () => {
|
30 |
+
alert('hello')
|
31 |
+
}
|
32 |
+
}
|
33 |
+
}"""
|
34 |
+
}
|
35 |
+
})
|
36 |
+
|
37 |
+
if __name__ == "__main__":
|
38 |
+
demo.queue().launch()
|
components/Markdown/demos/custom-tag3.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_gradio_components as mgr
|
7 |
+
|
8 |
+
options = ["a", "b", "c"]
|
9 |
+
|
10 |
+
|
11 |
+
def resolve_assets(relative_path):
|
12 |
+
return os.path.join(os.path.dirname(__file__), "../resources",
|
13 |
+
relative_path)
|
14 |
+
|
15 |
+
|
16 |
+
with open(resolve_assets("./custom_components/custom_select.js"), 'r') as f:
|
17 |
+
custom_select_js = f.read()
|
18 |
+
|
19 |
+
with gr.Blocks() as demo:
|
20 |
+
mgr.Markdown(value=f"""
|
21 |
+
custom tag: <custom-select options='{json.dumps(options)}'></custom-select>
|
22 |
+
""",
|
23 |
+
custom_components={
|
24 |
+
"custom-select": {
|
25 |
+
"props": ["options"],
|
26 |
+
"js": custom_select_js,
|
27 |
+
}
|
28 |
+
})
|
29 |
+
|
30 |
+
if __name__ == "__main__":
|
31 |
+
demo.queue().launch()
|
components/Markdown/demos/custom-tag4.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_gradio_components as mgr
|
7 |
+
|
8 |
+
options = ["a", "b", "c"]
|
9 |
+
|
10 |
+
|
11 |
+
def resolve_assets(relative_path):
|
12 |
+
return os.path.join(os.path.dirname(__file__), "../resources",
|
13 |
+
relative_path)
|
14 |
+
|
15 |
+
|
16 |
+
with open(resolve_assets("./custom_components/custom_select.js"), 'r') as f:
|
17 |
+
custom_select_js = f.read()
|
18 |
+
|
19 |
+
|
20 |
+
# 注意一定要显示指明类型,gradio 使用 ioc 机制注入值
|
21 |
+
def fn(data: gr.EventData):
|
22 |
+
# custom {'index': [0, 1, 0], 'tag': 'custom-select', 'tag_index': 0, 'value': 'option A'}
|
23 |
+
print("custom value", data._data)
|
24 |
+
|
25 |
+
|
26 |
+
with gr.Blocks() as demo:
|
27 |
+
md = mgr.Markdown(value=f"""
|
28 |
+
custom tag: <custom-select options='{json.dumps(options)}'></custom-select>
|
29 |
+
""",
|
30 |
+
custom_components={
|
31 |
+
"custom-select": {
|
32 |
+
"props": ["options"],
|
33 |
+
"js": custom_select_js,
|
34 |
+
}
|
35 |
+
})
|
36 |
+
md.custom(fn=fn)
|
37 |
+
|
38 |
+
if __name__ == "__main__":
|
39 |
+
demo.queue().launch()
|
components/Markdown/demos/custom_tags/accordion/accordion-title.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
with gr.Blocks() as demo:
|
6 |
+
mgr.Markdown(f"""
|
7 |
+
<accordion>
|
8 |
+
|
9 |
+
::accordion-title[调用 `tool`]
|
10 |
+
|
11 |
+
```json
|
12 |
+
{{"text": "风和日丽", "resolution": "1024*1024"}}
|
13 |
+
```
|
14 |
+
|
15 |
+
</accordion>
|
16 |
+
""")
|
17 |
+
|
18 |
+
if __name__ == "__main__":
|
19 |
+
demo.queue().launch()
|
components/Markdown/demos/custom_tags/accordion/basic.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
with gr.Blocks() as demo:
|
6 |
+
mgr.Markdown(f"""
|
7 |
+
<accordion title="调用 tool">
|
8 |
+
|
9 |
+
```json
|
10 |
+
{{"text": "风和日丽", "resolution": "1024*1024"}}
|
11 |
+
```
|
12 |
+
|
13 |
+
</accordion>
|
14 |
+
""")
|
15 |
+
|
16 |
+
if __name__ == "__main__":
|
17 |
+
demo.queue().launch()
|
components/Markdown/demos/custom_tags/select-box/basic.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
options = [{"label": "A", "value": "a"}, "b", "c"]
|
8 |
+
|
9 |
+
with gr.Blocks() as demo:
|
10 |
+
mgr.Markdown(
|
11 |
+
f"""Single Select: <select-box options='{json.dumps(options)}' select-once></select-box>
|
12 |
+
|
13 |
+
Multiple Select:<select-box type="checkbox" options='{json.dumps(options)}' select-once submit-text="Submit"></select-box>
|
14 |
+
|
15 |
+
Vertical Direction:
|
16 |
+
|
17 |
+
<select-box direction="vertical" type="checkbox" options='{json.dumps(options)}' select-once submit-text="Submit"></select-box>
|
18 |
+
""", )
|
19 |
+
|
20 |
+
if __name__ == "__main__":
|
21 |
+
demo.queue().launch()
|
components/Markdown/demos/custom_tags/select-box/card_shape.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_gradio_components as mgr
|
7 |
+
|
8 |
+
# card 支持额外传入 imgSrc 属性作为样式封面
|
9 |
+
options = [{
|
10 |
+
"label":
|
11 |
+
"A",
|
12 |
+
"imgSrc":
|
13 |
+
os.path.join(os.path.dirname(__file__), '../../../resources/screen.jpeg'),
|
14 |
+
"value":
|
15 |
+
"a"
|
16 |
+
}, "b", "c", "d"]
|
17 |
+
|
18 |
+
with gr.Blocks() as demo:
|
19 |
+
mgr.Markdown(
|
20 |
+
f"""<select-box shape="card" options='{json.dumps(options)}' select-once equal-height></select-box>
|
21 |
+
|
22 |
+
Custom Columns:
|
23 |
+
|
24 |
+
<select-box shape="card" columns="2" options='{json.dumps(options)}' select-once equal-height></select-box>
|
25 |
+
|
26 |
+
Vertical Direction:
|
27 |
+
|
28 |
+
<select-box shape="card" direction="vertical" options='{json.dumps(options)}' select-once equal-height></select-box>
|
29 |
+
""")
|
30 |
+
|
31 |
+
if __name__ == "__main__":
|
32 |
+
demo.queue().launch()
|
components/Markdown/demos/custom_tags/select-box/card_shape_width_auto.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
import modelscope_gradio_components as mgr
|
7 |
+
|
8 |
+
# card 支持额外传入 imgSrc 属性作为样式封面
|
9 |
+
options = [{
|
10 |
+
"label":
|
11 |
+
"A",
|
12 |
+
"imgSrc":
|
13 |
+
os.path.join(os.path.dirname(__file__), '../../../resources/screen.jpeg'),
|
14 |
+
"value":
|
15 |
+
"a"
|
16 |
+
}, "b", "c", "d"]
|
17 |
+
|
18 |
+
with gr.Blocks() as demo:
|
19 |
+
mgr.Markdown(
|
20 |
+
# 填写 item-width="auto"
|
21 |
+
f"""
|
22 |
+
<select-box shape="card" direction="vertical" options='{json.dumps(options)}' select-once item-width="auto"></select-box>
|
23 |
+
""", )
|
24 |
+
|
25 |
+
if __name__ == "__main__":
|
26 |
+
demo.queue().launch()
|
components/Markdown/demos/custom_tags/select-box/python_events.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
options = [{"label": "A", "value": "a"}, "b", "c"]
|
8 |
+
|
9 |
+
|
10 |
+
def fn(data: gr.EventData):
|
11 |
+
custom_data = data._data
|
12 |
+
if (custom_data["tag"] == "select-box"):
|
13 |
+
print(custom_data["value"]) # 用户选择的值,与 options 中的 value 对应
|
14 |
+
|
15 |
+
|
16 |
+
with gr.Blocks() as demo:
|
17 |
+
md = mgr.Markdown(
|
18 |
+
f"<select-box options='{json.dumps(options)}' select-once></select-box>"
|
19 |
+
)
|
20 |
+
md.custom(fn=fn)
|
21 |
+
|
22 |
+
if __name__ == "__main__":
|
23 |
+
demo.queue().launch()
|
components/Markdown/demos/multimodal.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
|
8 |
+
def resolve_assets(relative_path):
|
9 |
+
return os.path.join(os.path.dirname(__file__), "../resources",
|
10 |
+
relative_path)
|
11 |
+
|
12 |
+
|
13 |
+
with gr.Blocks() as demo:
|
14 |
+
mgr.Markdown(f"""
|
15 |
+
图片
|
16 |
+
|
17 |
+
![image]({resolve_assets("bot.jpeg")})
|
18 |
+
|
19 |
+
<img src="{resolve_assets("user.jpeg")}" />
|
20 |
+
|
21 |
+
视频
|
22 |
+
|
23 |
+
<video src="{resolve_assets("dog.mp4")}"></video>
|
24 |
+
|
25 |
+
音频
|
26 |
+
|
27 |
+
<audio src="{resolve_assets("audio.wav")}"></audio>
|
28 |
+
""")
|
29 |
+
|
30 |
+
if __name__ == "__main__":
|
31 |
+
demo.queue().launch()
|
components/Markdown/demos/select-box.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
import modelscope_gradio_components as mgr
|
6 |
+
|
7 |
+
# label 为对用户展示值,value 为实际选择值
|
8 |
+
options = [{"label": "A", "value": "a"}, "b", "c"]
|
9 |
+
|
10 |
+
with gr.Blocks() as demo:
|
11 |
+
mgr.Markdown(f"""
|
12 |
+
Single Select: <select-box options='{json.dumps(options)}' select-once></select-box>
|
13 |
+
|
14 |
+
Multiple Select:<select-box type="checkbox" options='{json.dumps(options)}' select-once submit-text="Submit"></select-box>
|
15 |
+
|
16 |
+
Vertical Direction:
|
17 |
+
|
18 |
+
<select-box direction="vertical" type="checkbox" options='{json.dumps(options)}' select-once submit-text="Submit"></select-box>
|
19 |
+
|
20 |
+
Card Shape:
|
21 |
+
|
22 |
+
<select-box shape="card" options='{json.dumps(options)}' select-once equal-height></select-box>
|
23 |
+
|
24 |
+
|
25 |
+
<select-box shape="card" columns="2" options='{json.dumps(options)}' select-once equal-height></select-box>
|
26 |
+
|
27 |
+
|
28 |
+
<select-box shape="card" direction="vertical" options='{json.dumps(options)}' select-once equal-height></select-box>
|
29 |
+
""")
|
30 |
+
|
31 |
+
if __name__ == "__main__":
|
32 |
+
demo.queue().launch()
|
components/Markdown/resources/audio.wav
ADDED
Binary file (44.8 kB). View file
|
|
components/Markdown/resources/bot.jpeg
ADDED
components/Markdown/resources/custom_components/custom_select.js
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(props, cc, { el, onMount }) => {
|
2 |
+
const options = JSON.parse(props.options);
|
3 |
+
el.innerHTML = `
|
4 |
+
${options
|
5 |
+
.map((option) => {
|
6 |
+
return `<div>
|
7 |
+
<label>${option} <input type="radio"/></label>
|
8 |
+
<div>`;
|
9 |
+
})
|
10 |
+
.join('')}
|
11 |
+
`;
|
12 |
+
onMount(() => {
|
13 |
+
const inputs = Array.from(el.getElementsByTagName('input'));
|
14 |
+
Array.from(el.getElementsByTagName('label')).forEach((label, i) => {
|
15 |
+
label.addEventListener('click', () => {
|
16 |
+
inputs.forEach((input) => {
|
17 |
+
input.checked = false;
|
18 |
+
});
|
19 |
+
const input = label.getElementsByTagName('input')[0];
|
20 |
+
input.checked = true;
|
21 |
+
// 通过 cc.dispatch 向 python 侧发送通知
|
22 |
+
cc.dispatch(options[i]);
|
23 |
+
});
|
24 |
+
});
|
25 |
+
});
|
26 |
+
};
|
components/Markdown/resources/dog.mp4
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:39d086ce29e48cf76e5042d2f3f0611ee46575f70fa3dc0c40dd4cfffde3d933
|
3 |
+
size 8626383
|
components/Markdown/resources/screen.jpeg
ADDED
components/Markdown/resources/user.jpeg
ADDED
components/MultimodalInput/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# MutilmodalInput
|
2 |
+
|
3 |
+
多模态输入框,支持上传文件、录音、照相等功能。
|
4 |
+
|
5 |
+
- 支持文本输入+文件上传共同提交
|
6 |
+
- 支持文件上传时的图片、音频预览
|
7 |
+
- 提交内容作为 Chatbot 输入多模态内容作为用户输入问题自动匹配
|
8 |
+
- 支持用户录音和拍照
|
9 |
+
|
10 |
+
## 如何使用
|
11 |
+
|
12 |
+
### 基本使用
|
13 |
+
|
14 |
+
<demo name="basic"></demo>
|
15 |
+
|
16 |
+
### 与 Chatbot 配合使用
|
17 |
+
|
18 |
+
<demo name="with_chatbot"></demo>
|
19 |
+
|
20 |
+
### 配置上传/提交按钮
|
21 |
+
|
22 |
+
<demo name="config_buttons"></demo>
|
23 |
+
|
24 |
+
### 允许用户录音或拍照
|
25 |
+
|
26 |
+
<demo name="upload_sources"></demo>
|
27 |
+
|
28 |
+
## API 及参数列表
|
29 |
+
|
30 |
+
以下 API 均为在原有 gradio Textbox 外的额外拓展参数。
|
31 |
+
|
32 |
+
### value
|
33 |
+
|
34 |
+
接口定义:
|
35 |
+
|
36 |
+
```python
|
37 |
+
class MultimodalInputData(GradioModel):
|
38 |
+
files: List[Union[FileData, str]] = []
|
39 |
+
text: str
|
40 |
+
```
|
41 |
+
|
42 |
+
### props
|
43 |
+
|
44 |
+
| 属性 | 类型 | 默认值 | 描述 |
|
45 |
+
| ------------------- | -------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------- |
|
46 |
+
| sources | list\[Literal\['upload', 'microphone','webcam'\]\] | \['upload'\] | 上传文件的类型列表。 "upload"会提供上文文件按钮。 "microphone"支持用户录音输入。 "webcam"支持用户照相生成图片或视频 |
|
47 |
+
| webcam_props | dict | None | webcam 组件属性,目前支持传入mirror_webcam(bool)、include_audio(bool) |
|
48 |
+
| upload_button_props | dict | None | 上传文件按钮属性,同 gradio UploadButton |
|
49 |
+
| submit_button_props | dict | None | 提交按钮属性,同 gradio Button |
|
50 |
+
| file_preview_props | dict | None | 文件预览组件属性,目前支持传入 height (int) |
|
components/MultimodalInput/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/MultimodalInput/demos/basic.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
|
6 |
+
def fn(value):
|
7 |
+
# value 包含 text 与 files
|
8 |
+
print(value.text, value.files)
|
9 |
+
|
10 |
+
|
11 |
+
with gr.Blocks() as demo:
|
12 |
+
input = mgr.MultimodalInput()
|
13 |
+
input.change(fn=fn, inputs=[input])
|
14 |
+
|
15 |
+
if __name__ == "__main__":
|
16 |
+
demo.queue().launch()
|
components/MultimodalInput/demos/config_buttons.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modelscope_gradio_components as mgr
|
4 |
+
|
5 |
+
|
6 |
+
def fn(value):
|
7 |
+
print(value.text, value.files)
|
8 |
+
|
9 |
+
|
10 |
+
with gr.Blocks() as demo:
|
11 |
+
input = mgr.MultimodalInput(upload_button_props=dict(variant="primary"),
|
12 |
+
submit_button_props=dict(visible=False))
|
13 |
+
input.change(fn=fn, inputs=[input])
|
14 |
+
|
15 |
+
if __name__ == "__main__":
|
16 |
+
demo.queue().launch()
|