Skip to content

Commit b0f44d4

Browse files
authored
feat: 补充算子文档和示例 (#282)
1 parent 709ebb5 commit b0f44d4

File tree

5 files changed

+514
-147
lines changed

5 files changed

+514
-147
lines changed

runtime/ops/README.md

Lines changed: 241 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,267 @@
1-
# 自定义算子开发指南
1+
# 自定义算子开发规范指南
22

3-
## 算子规范
3+
本文档旨在为开发者提供一套标准的自定义数据处理算子开发规范。通过遵循本指南,您可以开发出能够无缝集成到数据处理系统中的高质量算子。
44

5-
### 算子元数据格式
5+
## 1. 目录结构规范
66

7-
每个自定义算子都需要包含一个 `metadata.yml` 文件:
7+
一个标准的算子开发包(Package)应包含以下核心文件。请确保文件命名准确,以便系统正确识别。
8+
9+
```text
10+
operator_package/
11+
├── __init__.py # [必要] 算子注册入口,用于将算子注册到全局工厂
12+
├── metadata.yml # [必要] 算子元数据、UI 参数定义及资源配置
13+
├── process.py # [必要] 算子核心逻辑代码
14+
├── requirements.txt # [可选] 算子运行所需的第三方 Python 依赖
15+
└── README.md # [可选] 算子功能说明文档
16+
17+
```
18+
19+
---
20+
21+
## 2. 元数据与配置 (metadata.yml)
22+
23+
`metadata.yml` 定义了算子在系统中的“身份”、前端显示的配置组件以及运行时资源限制。
24+
25+
### 2.1 基础信息配置
26+
27+
| 字段 | 说明 | 示例 |
28+
| --- |------------------------------------| --- |
29+
| `name` | 算子显示名称 | 测试算子 |
30+
| `description` | 算子描述 | 这是一个测试算子。 |
31+
| `language` | 算子使用的语言,当前仅支持python | python |
32+
| `raw_id` | **关键字段**,必须与 `process.py` 中的类名完全一致 | TestMapper |
33+
| `version` | 语义化版本号 | 1.0.0 |
34+
| `modal` / `inputs` / `outputs` | 支持的数据模态 (text/image/audio/video) | text |
35+
36+
### 2.2 算子版本更新日志 (release)
37+
38+
定义算子当前版本较上版本更新内容。
839

940
```yaml
10-
name: '测试算子'
11-
description: '这是一个测试算子。'
12-
language: 'python'
13-
vendor: 'huawei'
14-
raw_id: 'TestMapper'
15-
version: '1.0.0'
16-
modal: 'text' # text/image/audio/video/multimodal
17-
inputs: 'text'
18-
outputs: 'text'
41+
release:
42+
- '首次发布'
43+
- '支持基本处理操作'
1944
```
2045
21-
### 算子实现
46+
### 2.2 运行时资源与指标 (runtime & metrics)
2247
23-
#### process.py
48+
定义算子运行时的资源配额及性能指标参考。
2449
25-
```python
26-
# -*- coding: utf-8 -*-
50+
```yaml
51+
runtime:
52+
memory: 10MB # 内存限制
53+
cpu: 1000m # CPU 核心数 (m代表毫核)
54+
gpu: 0.1 # GPU 卡数
55+
npu: 0.1 # NPU 卡数
56+
storage: 10MB # 存储空间
2757

28-
# 导入所需数据结构,可以通过以下方式直接导入使用
29-
# 提供两种算子类:
30-
# Mapper用于映射和转换数据,使用时直接修改数据内容
31-
from datamate.core.base_op import Mapper
58+
metrics: # 算子性能参考指标
59+
- name: '吞吐量'
60+
metric: '20 images/sec'
61+
- name: '准确率'
62+
metric: '99.5%'
63+
```
3264
33-
class TestMapper(Mapper):
34-
def execute(self, sample):
35-
sample[self.text_key] += "\n新增的数据"
36-
return sample
65+
### 2.3 参数设置 (settings) - UI 组件规范
66+
67+
通过 `settings` 字段,开发者可以自定义用户在前端界面配置算子时的交互组件。系统支持以下类型:
3768

69+
* **Slider (滑动条)** - 用于数值范围调整
70+
```yaml
71+
sliderParam: # 参数的唯一标识符,process.py 中通过该参数获取值
72+
name: '参数展示名称' # 界面上显示给用户的参数标题
73+
description: '参数展示描述' # 用户鼠标悬停时显示的详细功能说明或帮助文本
74+
type: 'slider' # 组件类型
75+
defaultVal: 0.5 # 算子加载时的初始值,必须位于 min 和 max 之间
76+
required: false # 是否必填
77+
min: 0 # [下限] 滑动条允许调整的最小值
78+
max: 1 # [上限] 滑动条允许调整的最大值
79+
step: 0.1 # [步长] 每次拖动的增量 (例如 0.1 代表保留一位小数,1 代表整数)
80+
```
3881

39-
# Filter用于过滤和选择性保留数据,使用时将需要过滤的数据的text或data置为空值
40-
from datamate.core.base_op import Filter
82+
* **Switch (开关)** - 用于布尔值控制
83+
```yaml
84+
switchParam:
85+
name: '参数展示名称'
86+
description: '参数展示描述'
87+
type: 'switch'
88+
defaultVal: 'true' # 注意 yaml 中布尔值建议使用引号或标准写法
89+
required: false # 是否必须参数
90+
checkedLabel: '选中' # 选中时的展示
91+
unCheckedLabel: '未选中' # 未选中时的展示
92+
```
4193

42-
class TestFilter(Filter):
43-
def execute(self, sample):
44-
if len(sample[self.text_key]) > 100:
45-
sample[self.text_key] += ""
46-
return sample
94+
* **Select / Radio (下拉 / 单选)** - 用于枚举选项
95+
```yaml
96+
selectParam:
97+
name: '参数展示名称'
98+
description: '参数展示描述'
99+
type: 'select' # 或 'radio'
100+
defaultVal: 'option1' # 默认后端传递值,为options其中一个选项
101+
required: false
102+
options:
103+
- label: '选项1' # 前端显示标签
104+
value: 'option1' # 后端传递值
105+
- label: '选项2'
106+
value: 'option2'
107+
```
47108

109+
* **Range (范围区间)**
110+
```yaml
111+
rangeParam:
112+
name: '参数展示名称'
113+
description: '参数展示描述'
114+
type: 'range'
115+
properties:
116+
- name: 'rangeLeft' # 范围下限
117+
type: 'inputNumber'
118+
defaultVal: 100
119+
min: 0
120+
max: 10000
121+
step: 1
122+
- name: 'rangeRight' # 范围上限
123+
type: 'inputNumber'
124+
defaultVal: 8000
125+
min: 0
126+
max: 10000
127+
step: 1
48128
```
49129

50-
其中,sample的数据结构如下所示:
51-
```json lines
52-
// 数据结构
53-
{
54-
"text": "数据文件的文本内容",
55-
"data": "多模态文件的内容",
56-
"fileName": "文件名称",
57-
"fileType": "文件类型",
58-
"filePath": "文件路径",
59-
"fileSize": "文件大小",
60-
"export_path": "保存的文件路径",
61-
"extraFileType": "导出的文件类型"
62-
}
63-
64-
// 数据示例
65-
{
66-
"text": "text",
67-
"data": "data",
68-
"fileName": "test",
69-
"fileType": "pdf",
70-
"filePath": "/dataset/test.pdf",
71-
"fileSize": "100B",
72-
"export_path": "/dataset/test.txt",
73-
"extraFileType": "txt"
74-
}
130+
* **Checkbox (多选)**
131+
```yaml
132+
checkboxParam:
133+
name: '参数展示名称'
134+
description: '参数展示描述'
135+
type: 'checkbox'
136+
defaultVal: 'option1,option2' # 多个值用逗号分隔
137+
required: false
138+
options:
139+
- label: '选项1'
140+
value: 'option1'
141+
- label: '选项2'
142+
value: 'option2'
143+
144+
```
145+
146+
* **Input (文本输入)**
147+
```yaml
148+
inputParam:
149+
name: '参数展示名称'
150+
description: '参数展示描述'
151+
type: 'input'
152+
defaultVal: '默认值'
153+
required: false
75154
```
76155

77-
#### \_\_init__.py
156+
---
157+
158+
## 3. 核心逻辑实现 (`process.py`)
159+
160+
`process.py` 是算子的执行主体。开发者需继承基础类并实现数据处理逻辑。
161+
162+
### 开发规范
163+
164+
1. **继承基类**:必须从 `datamate.core.base_op` 继承 `Mapper`或 `Filter`。
165+
2. **类名一致性**:Python 类名建议与后续 `metadata.yml` 中的 `raw_id` 保持一致。
166+
3. **Execute 方法**:必须实现 `execute` 方法,接收 `sample` (字典) 并返回处理后的字典。
167+
168+
### 代码模板
78169

79170
```python
80-
# -*- coding: utf-8 -*-
171+
from typing import Dict, Any
172+
from datamate.core.base_op import Mapper
173+
174+
class YourOperatorName(Mapper):
175+
"""
176+
算子类名建议使用驼峰命名法定义,例如 TestMapper
177+
"""
178+
179+
def __init__(self, *args, **kwargs):
180+
super().__init__(*args, **kwargs)
181+
self.slider_param = float(kwargs.get("sliderParam", 0.5))
182+
self.switch_param = kwargs.get('switchParam', False)
183+
self.select_param = kwargs.get('selectParam', '')
184+
self.radio_param = kwargs.get('radioParam', '')
185+
self.range_param = kwargs.get('rangeParam', [0, 0])
186+
self.checkbox_param = kwargs.get('checkboxParam', [])
187+
self.input_param = kwargs.get('inputParam', '').strip()
188+
189+
def execute(self, sample: Dict[str, Any]) -> Dict[str, Any]:
190+
"""
191+
核心处理逻辑
192+
:param sample: 输入的数据样本,通常包含 text_key 等字段
193+
:return: 处理后的数据样本
194+
"""
195+
# 示例:获取文本并进行修改
196+
# input_text = sample['text']
197+
# processed_text = do_something(input_text)
198+
# sample['text'] = processed_text
199+
200+
return sample
201+
202+
```
203+
204+
---
205+
206+
## 4. 算子注册 (`__init__.py`)
81207

82-
# 导入OPERATORS用于进行模块注册,可以通过以下方式直接导入使用
208+
`__init__.py` 用于将开发好的算子注册到系统中。
209+
210+
### 注册规范
211+
212+
使用 `OPERATORS.register_module` 方法进行注册。
213+
214+
* **module_name**: 对应 `metadata.yml` 中的 `raw_id` 及 Python 类名。
215+
* **module_path**: 指向 `process.py` 的引用路径(注意路径层级)。
216+
217+
### 代码模板
218+
219+
```python
220+
# -*- coding: utf-8 -*-
83221
from datamate.core.base_op import OPERATORS
84222
85-
# module_name必须填写算子类名称;module_path中须替换模块的算子压缩包名称:python_operator.user.压缩包名.process
86-
OPERATORS.register_module(module_name='TestMapper',
87-
module_path="ops.user.test_operator.process")
223+
# 假设 process.py 位于 operator_package 目录下
224+
OPERATORS.register_module(
225+
module_name='YourOperatorName',
226+
module_path="ops.user.operator_package.process"
227+
)
88228
89229
```
230+
231+
---
232+
233+
## 5. 开发注意事项
234+
235+
1. **依赖管理**:如果算子依赖非标准库(如 pandas, numpy),请在 `requirements.txt` 中列出。
236+
2. **异常处理**:在 `process.py` 中建议添加适当的 try-catch 逻辑,避免单条数据异常导致整个任务崩溃。
237+
3. **数据类型**:在 `metadata.yml` 中定义的参数类型(如 slider 返回 float,input 返回 string),在 Python 代码中使用时需注意类型转换。
238+
239+
---
240+
241+
## 6. 算子打包与上传
242+
243+
开发完成后,需将所有文件打包为一个压缩包进行上传。**包名必须严格遵循注册路径规范**。
244+
245+
### 打包规范
246+
247+
1. **文件完整性**:压缩包内必须包含 `__init__.py`, `metadata.yml`, `process.py` 及相关依赖。
248+
2. **命名一致性(重要)**:压缩包的文件名(不含后缀)必须与 `__init__.py` 中 `module_path` 所指定的**包目录名**保持一致。
249+
250+
### 示例说明
251+
252+
假设您在 `__init__.py` 中的注册代码如下:
253+
254+
```python
255+
OPERATORS.register_module(
256+
module_name='TestMapper',
257+
# 这里 ops.user.my_custom_op.process 中的 'my_custom_op' 为包目录名
258+
module_path="ops.user.my_custom_op.process"
259+
)
260+
261+
```
262+
263+
则您的压缩包名称必须命名为:
264+
265+
> **`my_custom_op.zip`** (或 .tar)
266+
267+
系统解压后将基于此名称构建导入路径,名称不一致将导致 `ModuleNotFoundError`。

0 commit comments

Comments
 (0)