dtflow 0.4.3__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dtflow-0.4.3 → dtflow-0.5.0}/PKG-INFO +107 -2
- {dtflow-0.4.3 → dtflow-0.5.0}/README.md +106 -1
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/__init__.py +34 -1
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/__main__.py +22 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/commands.py +5 -0
- dtflow-0.5.0/dtflow/cli/validate.py +152 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/core.py +154 -0
- dtflow-0.5.0/dtflow/framework.py +610 -0
- dtflow-0.5.0/dtflow/schema.py +508 -0
- dtflow-0.5.0/tests/test_framework.py +204 -0
- dtflow-0.5.0/tests/test_schema.py +547 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/.gitignore +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/__init__.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/clean.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/common.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/io_ops.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/lineage.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/pipeline.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/sample.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/stats.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/cli/transform.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/converters.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/lineage.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/mcp/__init__.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/mcp/__main__.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/mcp/cli.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/mcp/docs.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/mcp/server.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/pipeline.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/presets.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/storage/__init__.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/storage/io.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/streaming.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/tokenizers.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/utils/__init__.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/utils/display.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/dtflow/utils/field_path.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/pyproject.toml +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/benchmark_io.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_converters.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_field_path.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_io.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_lineage.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_pipeline.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_streaming.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_tokenizers.py +0 -0
- {dtflow-0.4.3 → dtflow-0.5.0}/tests/test_transformer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dtflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: A flexible data transformation tool for ML training formats (SFT, RLHF, Pretrain)
|
|
5
5
|
Project-URL: Homepage, https://github.com/yourusername/DataTransformer
|
|
6
6
|
Project-URL: Documentation, https://github.com/yourusername/DataTransformer#readme
|
|
@@ -129,7 +129,7 @@ dt.filter(lambda x: x.language == "zh")
|
|
|
129
129
|
### 数据验证
|
|
130
130
|
|
|
131
131
|
```python
|
|
132
|
-
#
|
|
132
|
+
# 简单验证,返回不通过的记录列表
|
|
133
133
|
errors = dt.validate(lambda x: len(x.messages) >= 2)
|
|
134
134
|
|
|
135
135
|
if errors:
|
|
@@ -137,6 +137,53 @@ if errors:
|
|
|
137
137
|
print(f"第 {e.index} 行: {e.error}")
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
### Schema 验证
|
|
141
|
+
|
|
142
|
+
使用 Schema 进行结构化数据验证:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from dtflow import Schema, Field, openai_chat_schema
|
|
146
|
+
|
|
147
|
+
# 使用预设 Schema
|
|
148
|
+
result = dt.validate_schema(openai_chat_schema)
|
|
149
|
+
print(result) # ValidationResult(valid=950, invalid=50, errors=[...])
|
|
150
|
+
|
|
151
|
+
# 自定义 Schema
|
|
152
|
+
schema = Schema({
|
|
153
|
+
"messages": Field(type="list", required=True, min_length=1),
|
|
154
|
+
"messages[*].role": Field(type="str", choices=["user", "assistant", "system"]),
|
|
155
|
+
"messages[*].content": Field(type="str", min_length=1),
|
|
156
|
+
"score": Field(type="float", min=0, max=1),
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
result = dt.validate_schema(schema)
|
|
160
|
+
|
|
161
|
+
# 过滤出有效数据
|
|
162
|
+
valid_dt = dt.validate_schema(schema, filter_invalid=True)
|
|
163
|
+
valid_dt.save("valid.jsonl")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**预设 Schema**:
|
|
167
|
+
|
|
168
|
+
| Schema 名称 | 用途 |
|
|
169
|
+
|------------|------|
|
|
170
|
+
| `openai_chat_schema` | OpenAI messages 格式验证 |
|
|
171
|
+
| `alpaca_schema` | Alpaca instruction/output 格式 |
|
|
172
|
+
| `sharegpt_schema` | ShareGPT conversations 格式 |
|
|
173
|
+
| `dpo_schema` | DPO prompt/chosen/rejected 格式 |
|
|
174
|
+
|
|
175
|
+
**Field 参数**:
|
|
176
|
+
|
|
177
|
+
| 参数 | 说明 | 示例 |
|
|
178
|
+
|------|------|------|
|
|
179
|
+
| `type` | 类型验证 | `"str"`, `"int"`, `"float"`, `"bool"`, `"list"`, `"dict"` |
|
|
180
|
+
| `required` | 是否必填 | `True` / `False` |
|
|
181
|
+
| `min` / `max` | 数值范围 | `min=0, max=1` |
|
|
182
|
+
| `min_length` / `max_length` | 长度范围 | `min_length=1` |
|
|
183
|
+
| `choices` | 枚举值 | `choices=["user", "assistant"]` |
|
|
184
|
+
| `pattern` | 正则匹配 | `pattern=r"^\d{4}-\d{2}-\d{2}$"` |
|
|
185
|
+
| `custom` | 自定义验证 | `custom=lambda x: x > 0` |
|
|
186
|
+
|
|
140
187
|
### 数据转换
|
|
141
188
|
|
|
142
189
|
```python
|
|
@@ -286,6 +333,58 @@ dt.transform(to_swift_vlm(images_field="images")).save("swift_vlm.jsonl")
|
|
|
286
333
|
# 输出: {"messages": [...], "images": ["/path/to/img.jpg"]}
|
|
287
334
|
```
|
|
288
335
|
|
|
336
|
+
### 训练框架一键导出
|
|
337
|
+
|
|
338
|
+
将数据导出为目标训练框架可直接使用的格式,自动生成配置文件:
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from dtflow import DataTransformer
|
|
342
|
+
|
|
343
|
+
dt = DataTransformer.load("data.jsonl")
|
|
344
|
+
|
|
345
|
+
# 1. 检查框架兼容性
|
|
346
|
+
result = dt.check_compatibility("llama-factory")
|
|
347
|
+
print(result)
|
|
348
|
+
# ✅ 兼容 - LLaMA-Factory (openai_chat)
|
|
349
|
+
# 或
|
|
350
|
+
# ❌ 不兼容 - 错误: xxx
|
|
351
|
+
|
|
352
|
+
# 2. 一键导出到 LLaMA-Factory
|
|
353
|
+
files = dt.export_for("llama-factory", "./llama_ready/")
|
|
354
|
+
# 生成文件:
|
|
355
|
+
# - ./llama_ready/custom_dataset.json # 数据文件
|
|
356
|
+
# - ./llama_ready/dataset_info.json # 数据集配置
|
|
357
|
+
# - ./llama_ready/train_args.yaml # 训练参数模板
|
|
358
|
+
|
|
359
|
+
# 3. 导出到 ms-swift
|
|
360
|
+
files = dt.export_for("swift", "./swift_ready/")
|
|
361
|
+
# 生成: data.jsonl + train_swift.sh
|
|
362
|
+
|
|
363
|
+
# 4. 导出到 Axolotl
|
|
364
|
+
files = dt.export_for("axolotl", "./axolotl_ready/")
|
|
365
|
+
# 生成: data.jsonl + config.yaml
|
|
366
|
+
|
|
367
|
+
# 指定数据集名称
|
|
368
|
+
dt.export_for("llama-factory", "./output/", dataset_name="my_sft_data")
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**支持的框架**:
|
|
372
|
+
|
|
373
|
+
| 框架 | 导出内容 | 使用方式 |
|
|
374
|
+
|------|---------|---------|
|
|
375
|
+
| `llama-factory` | data.json + dataset_info.json + train_args.yaml | `llamafactory-cli train train_args.yaml` |
|
|
376
|
+
| `swift` | data.jsonl + train_swift.sh | `bash train_swift.sh` |
|
|
377
|
+
| `axolotl` | data.jsonl + config.yaml | `accelerate launch -m axolotl.cli.train config.yaml` |
|
|
378
|
+
|
|
379
|
+
**自动格式检测**:
|
|
380
|
+
|
|
381
|
+
| 检测到的格式 | 数据结构 |
|
|
382
|
+
|------------|---------|
|
|
383
|
+
| `openai_chat` | `{"messages": [{"role": "user", ...}]}` |
|
|
384
|
+
| `alpaca` | `{"instruction": ..., "output": ...}` |
|
|
385
|
+
| `sharegpt` | `{"conversations": [{"from": "human", ...}]}` |
|
|
386
|
+
| `dpo` | `{"prompt": ..., "chosen": ..., "rejected": ...}` |
|
|
387
|
+
|
|
289
388
|
### 其他操作
|
|
290
389
|
|
|
291
390
|
```python
|
|
@@ -361,6 +460,12 @@ dt concat a.jsonl b.jsonl -o merged.jsonl
|
|
|
361
460
|
|
|
362
461
|
# 数据统计
|
|
363
462
|
dt stats data.jsonl
|
|
463
|
+
|
|
464
|
+
# 数据验证
|
|
465
|
+
dt validate data.jsonl --preset=openai_chat # 使用预设 schema 验证
|
|
466
|
+
dt validate data.jsonl --preset=alpaca --verbose # 详细输出
|
|
467
|
+
dt validate data.jsonl --preset=sharegpt --filter-invalid -o valid.jsonl # 过滤出有效数据
|
|
468
|
+
dt validate data.jsonl --preset=dpo --max-errors=100 # 限制错误输出数量
|
|
364
469
|
```
|
|
365
470
|
|
|
366
471
|
### 字段路径语法
|
|
@@ -53,7 +53,7 @@ dt.filter(lambda x: x.language == "zh")
|
|
|
53
53
|
### 数据验证
|
|
54
54
|
|
|
55
55
|
```python
|
|
56
|
-
#
|
|
56
|
+
# 简单验证,返回不通过的记录列表
|
|
57
57
|
errors = dt.validate(lambda x: len(x.messages) >= 2)
|
|
58
58
|
|
|
59
59
|
if errors:
|
|
@@ -61,6 +61,53 @@ if errors:
|
|
|
61
61
|
print(f"第 {e.index} 行: {e.error}")
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
### Schema 验证
|
|
65
|
+
|
|
66
|
+
使用 Schema 进行结构化数据验证:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from dtflow import Schema, Field, openai_chat_schema
|
|
70
|
+
|
|
71
|
+
# 使用预设 Schema
|
|
72
|
+
result = dt.validate_schema(openai_chat_schema)
|
|
73
|
+
print(result) # ValidationResult(valid=950, invalid=50, errors=[...])
|
|
74
|
+
|
|
75
|
+
# 自定义 Schema
|
|
76
|
+
schema = Schema({
|
|
77
|
+
"messages": Field(type="list", required=True, min_length=1),
|
|
78
|
+
"messages[*].role": Field(type="str", choices=["user", "assistant", "system"]),
|
|
79
|
+
"messages[*].content": Field(type="str", min_length=1),
|
|
80
|
+
"score": Field(type="float", min=0, max=1),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
result = dt.validate_schema(schema)
|
|
84
|
+
|
|
85
|
+
# 过滤出有效数据
|
|
86
|
+
valid_dt = dt.validate_schema(schema, filter_invalid=True)
|
|
87
|
+
valid_dt.save("valid.jsonl")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**预设 Schema**:
|
|
91
|
+
|
|
92
|
+
| Schema 名称 | 用途 |
|
|
93
|
+
|------------|------|
|
|
94
|
+
| `openai_chat_schema` | OpenAI messages 格式验证 |
|
|
95
|
+
| `alpaca_schema` | Alpaca instruction/output 格式 |
|
|
96
|
+
| `sharegpt_schema` | ShareGPT conversations 格式 |
|
|
97
|
+
| `dpo_schema` | DPO prompt/chosen/rejected 格式 |
|
|
98
|
+
|
|
99
|
+
**Field 参数**:
|
|
100
|
+
|
|
101
|
+
| 参数 | 说明 | 示例 |
|
|
102
|
+
|------|------|------|
|
|
103
|
+
| `type` | 类型验证 | `"str"`, `"int"`, `"float"`, `"bool"`, `"list"`, `"dict"` |
|
|
104
|
+
| `required` | 是否必填 | `True` / `False` |
|
|
105
|
+
| `min` / `max` | 数值范围 | `min=0, max=1` |
|
|
106
|
+
| `min_length` / `max_length` | 长度范围 | `min_length=1` |
|
|
107
|
+
| `choices` | 枚举值 | `choices=["user", "assistant"]` |
|
|
108
|
+
| `pattern` | 正则匹配 | `pattern=r"^\d{4}-\d{2}-\d{2}$"` |
|
|
109
|
+
| `custom` | 自定义验证 | `custom=lambda x: x > 0` |
|
|
110
|
+
|
|
64
111
|
### 数据转换
|
|
65
112
|
|
|
66
113
|
```python
|
|
@@ -210,6 +257,58 @@ dt.transform(to_swift_vlm(images_field="images")).save("swift_vlm.jsonl")
|
|
|
210
257
|
# 输出: {"messages": [...], "images": ["/path/to/img.jpg"]}
|
|
211
258
|
```
|
|
212
259
|
|
|
260
|
+
### 训练框架一键导出
|
|
261
|
+
|
|
262
|
+
将数据导出为目标训练框架可直接使用的格式,自动生成配置文件:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
from dtflow import DataTransformer
|
|
266
|
+
|
|
267
|
+
dt = DataTransformer.load("data.jsonl")
|
|
268
|
+
|
|
269
|
+
# 1. 检查框架兼容性
|
|
270
|
+
result = dt.check_compatibility("llama-factory")
|
|
271
|
+
print(result)
|
|
272
|
+
# ✅ 兼容 - LLaMA-Factory (openai_chat)
|
|
273
|
+
# 或
|
|
274
|
+
# ❌ 不兼容 - 错误: xxx
|
|
275
|
+
|
|
276
|
+
# 2. 一键导出到 LLaMA-Factory
|
|
277
|
+
files = dt.export_for("llama-factory", "./llama_ready/")
|
|
278
|
+
# 生成文件:
|
|
279
|
+
# - ./llama_ready/custom_dataset.json # 数据文件
|
|
280
|
+
# - ./llama_ready/dataset_info.json # 数据集配置
|
|
281
|
+
# - ./llama_ready/train_args.yaml # 训练参数模板
|
|
282
|
+
|
|
283
|
+
# 3. 导出到 ms-swift
|
|
284
|
+
files = dt.export_for("swift", "./swift_ready/")
|
|
285
|
+
# 生成: data.jsonl + train_swift.sh
|
|
286
|
+
|
|
287
|
+
# 4. 导出到 Axolotl
|
|
288
|
+
files = dt.export_for("axolotl", "./axolotl_ready/")
|
|
289
|
+
# 生成: data.jsonl + config.yaml
|
|
290
|
+
|
|
291
|
+
# 指定数据集名称
|
|
292
|
+
dt.export_for("llama-factory", "./output/", dataset_name="my_sft_data")
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**支持的框架**:
|
|
296
|
+
|
|
297
|
+
| 框架 | 导出内容 | 使用方式 |
|
|
298
|
+
|------|---------|---------|
|
|
299
|
+
| `llama-factory` | data.json + dataset_info.json + train_args.yaml | `llamafactory-cli train train_args.yaml` |
|
|
300
|
+
| `swift` | data.jsonl + train_swift.sh | `bash train_swift.sh` |
|
|
301
|
+
| `axolotl` | data.jsonl + config.yaml | `accelerate launch -m axolotl.cli.train config.yaml` |
|
|
302
|
+
|
|
303
|
+
**自动格式检测**:
|
|
304
|
+
|
|
305
|
+
| 检测到的格式 | 数据结构 |
|
|
306
|
+
|------------|---------|
|
|
307
|
+
| `openai_chat` | `{"messages": [{"role": "user", ...}]}` |
|
|
308
|
+
| `alpaca` | `{"instruction": ..., "output": ...}` |
|
|
309
|
+
| `sharegpt` | `{"conversations": [{"from": "human", ...}]}` |
|
|
310
|
+
| `dpo` | `{"prompt": ..., "chosen": ..., "rejected": ...}` |
|
|
311
|
+
|
|
213
312
|
### 其他操作
|
|
214
313
|
|
|
215
314
|
```python
|
|
@@ -285,6 +384,12 @@ dt concat a.jsonl b.jsonl -o merged.jsonl
|
|
|
285
384
|
|
|
286
385
|
# 数据统计
|
|
287
386
|
dt stats data.jsonl
|
|
387
|
+
|
|
388
|
+
# 数据验证
|
|
389
|
+
dt validate data.jsonl --preset=openai_chat # 使用预设 schema 验证
|
|
390
|
+
dt validate data.jsonl --preset=alpaca --verbose # 详细输出
|
|
391
|
+
dt validate data.jsonl --preset=sharegpt --filter-invalid -o valid.jsonl # 过滤出有效数据
|
|
392
|
+
dt validate data.jsonl --preset=dpo --max-errors=100 # 限制错误输出数量
|
|
288
393
|
```
|
|
289
394
|
|
|
290
395
|
### 字段路径语法
|
|
@@ -4,6 +4,7 @@ DataTransformer: 简洁的数据格式转换工具
|
|
|
4
4
|
核心功能:
|
|
5
5
|
- DataTransformer: 数据加载、转换、保存
|
|
6
6
|
- presets: 预设转换模板 (openai_chat, alpaca, sharegpt, dpo_pair, simple_qa)
|
|
7
|
+
- schema: 数据结构验证 (Schema, Field)
|
|
7
8
|
- tokenizers: Token 统计和过滤
|
|
8
9
|
- converters: HuggingFace/OpenAI 等格式转换
|
|
9
10
|
"""
|
|
@@ -26,6 +27,23 @@ from .converters import ( # LLaMA-Factory 扩展; ms-swift
|
|
|
26
27
|
)
|
|
27
28
|
from .core import DataTransformer, DictWrapper, TransformError, TransformErrors
|
|
28
29
|
from .presets import get_preset, list_presets
|
|
30
|
+
from .schema import (
|
|
31
|
+
Field,
|
|
32
|
+
Schema,
|
|
33
|
+
ValidationError,
|
|
34
|
+
ValidationResult,
|
|
35
|
+
alpaca_schema,
|
|
36
|
+
dpo_schema,
|
|
37
|
+
openai_chat_schema,
|
|
38
|
+
sharegpt_schema,
|
|
39
|
+
validate_data,
|
|
40
|
+
)
|
|
41
|
+
from .framework import (
|
|
42
|
+
CompatibilityResult,
|
|
43
|
+
check_compatibility,
|
|
44
|
+
detect_format,
|
|
45
|
+
export_for,
|
|
46
|
+
)
|
|
29
47
|
from .storage import load_data, sample_file, save_data
|
|
30
48
|
from .streaming import StreamingTransformer, load_sharded, load_stream, process_shards
|
|
31
49
|
from .tokenizers import (
|
|
@@ -42,7 +60,7 @@ from .tokenizers import (
|
|
|
42
60
|
token_stats,
|
|
43
61
|
)
|
|
44
62
|
|
|
45
|
-
__version__ = "0.
|
|
63
|
+
__version__ = "0.5.0"
|
|
46
64
|
|
|
47
65
|
__all__ = [
|
|
48
66
|
# core
|
|
@@ -53,6 +71,21 @@ __all__ = [
|
|
|
53
71
|
# presets
|
|
54
72
|
"get_preset",
|
|
55
73
|
"list_presets",
|
|
74
|
+
# schema
|
|
75
|
+
"Schema",
|
|
76
|
+
"Field",
|
|
77
|
+
"ValidationResult",
|
|
78
|
+
"ValidationError",
|
|
79
|
+
"validate_data",
|
|
80
|
+
"openai_chat_schema",
|
|
81
|
+
"alpaca_schema",
|
|
82
|
+
"dpo_schema",
|
|
83
|
+
"sharegpt_schema",
|
|
84
|
+
# framework
|
|
85
|
+
"CompatibilityResult",
|
|
86
|
+
"check_compatibility",
|
|
87
|
+
"detect_format",
|
|
88
|
+
"export_for",
|
|
56
89
|
# storage
|
|
57
90
|
"save_data",
|
|
58
91
|
"load_data",
|
|
@@ -18,6 +18,7 @@ Commands:
|
|
|
18
18
|
clean 数据清洗
|
|
19
19
|
run 执行 Pipeline 配置文件
|
|
20
20
|
history 显示数据血缘历史
|
|
21
|
+
validate 使用 Schema 验证数据格式
|
|
21
22
|
mcp MCP 服务管理(install/uninstall/status)
|
|
22
23
|
logs 日志查看工具使用说明
|
|
23
24
|
"""
|
|
@@ -40,6 +41,7 @@ from .cli.commands import stats as _stats
|
|
|
40
41
|
from .cli.commands import tail as _tail
|
|
41
42
|
from .cli.commands import token_stats as _token_stats
|
|
42
43
|
from .cli.commands import transform as _transform
|
|
44
|
+
from .cli.commands import validate as _validate
|
|
43
45
|
|
|
44
46
|
# 创建主应用
|
|
45
47
|
app = typer.Typer(
|
|
@@ -211,6 +213,26 @@ def history(
|
|
|
211
213
|
_history(filename, json)
|
|
212
214
|
|
|
213
215
|
|
|
216
|
+
# ============ 验证命令 ============
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@app.command()
|
|
220
|
+
def validate(
|
|
221
|
+
filename: str = typer.Argument(..., help="输入文件路径"),
|
|
222
|
+
preset: Optional[str] = typer.Option(
|
|
223
|
+
None, "--preset", "-p", help="预设 Schema: openai_chat, alpaca, dpo, sharegpt"
|
|
224
|
+
),
|
|
225
|
+
output: Optional[str] = typer.Option(None, "--output", "-o", help="输出有效数据的文件路径"),
|
|
226
|
+
filter: bool = typer.Option(
|
|
227
|
+
False, "--filter", "-f", help="过滤无效数据并保存"
|
|
228
|
+
),
|
|
229
|
+
max_errors: int = typer.Option(20, "--max-errors", help="最多显示的错误数量"),
|
|
230
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="显示详细信息"),
|
|
231
|
+
):
|
|
232
|
+
"""使用预设 Schema 验证数据格式"""
|
|
233
|
+
_validate(filename, preset, output, filter, max_errors, verbose)
|
|
234
|
+
|
|
235
|
+
|
|
214
236
|
# ============ 工具命令 ============
|
|
215
237
|
|
|
216
238
|
|
|
@@ -33,6 +33,9 @@ from .pipeline import run
|
|
|
33
33
|
# 血缘追踪命令
|
|
34
34
|
from .lineage import history
|
|
35
35
|
|
|
36
|
+
# 验证命令
|
|
37
|
+
from .validate import validate
|
|
38
|
+
|
|
36
39
|
__all__ = [
|
|
37
40
|
# 采样
|
|
38
41
|
"sample",
|
|
@@ -53,4 +56,6 @@ __all__ = [
|
|
|
53
56
|
"run",
|
|
54
57
|
# 血缘
|
|
55
58
|
"history",
|
|
59
|
+
# 验证
|
|
60
|
+
"validate",
|
|
56
61
|
]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI Schema 验证命令
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from ..schema import (
|
|
9
|
+
Schema,
|
|
10
|
+
Field,
|
|
11
|
+
alpaca_schema,
|
|
12
|
+
dpo_schema,
|
|
13
|
+
openai_chat_schema,
|
|
14
|
+
sharegpt_schema,
|
|
15
|
+
)
|
|
16
|
+
from ..storage.io import load_data, save_data
|
|
17
|
+
from .common import _check_file_format
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# 预设 Schema 映射
|
|
21
|
+
PRESET_SCHEMAS = {
|
|
22
|
+
"openai_chat": openai_chat_schema,
|
|
23
|
+
"openai-chat": openai_chat_schema,
|
|
24
|
+
"chat": openai_chat_schema,
|
|
25
|
+
"alpaca": alpaca_schema,
|
|
26
|
+
"dpo": dpo_schema,
|
|
27
|
+
"dpo_pair": dpo_schema,
|
|
28
|
+
"sharegpt": sharegpt_schema,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def validate(
|
|
33
|
+
filename: str,
|
|
34
|
+
preset: Optional[str] = None,
|
|
35
|
+
output: Optional[str] = None,
|
|
36
|
+
filter_invalid: bool = False,
|
|
37
|
+
max_errors: int = 20,
|
|
38
|
+
verbose: bool = False,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""
|
|
41
|
+
使用 Schema 验证数据文件。
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
filename: 输入文件路径
|
|
45
|
+
preset: 预设 Schema 名称 (openai_chat, alpaca, dpo, sharegpt)
|
|
46
|
+
output: 输出文件路径(保存有效数据)
|
|
47
|
+
filter_invalid: 过滤无效数据并保存
|
|
48
|
+
max_errors: 最多显示的错误数量
|
|
49
|
+
verbose: 显示详细信息
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
dt validate data.jsonl --preset=openai_chat
|
|
53
|
+
dt validate data.jsonl --preset=alpaca -o valid.jsonl
|
|
54
|
+
dt validate data.jsonl --preset=chat --filter
|
|
55
|
+
"""
|
|
56
|
+
filepath = Path(filename)
|
|
57
|
+
|
|
58
|
+
if not filepath.exists():
|
|
59
|
+
print(f"错误: 文件不存在 - {filename}")
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
if not _check_file_format(filepath):
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
# 确定 Schema
|
|
66
|
+
if preset is None:
|
|
67
|
+
# 列出可用的预设
|
|
68
|
+
print("请指定预设 Schema (--preset):")
|
|
69
|
+
print()
|
|
70
|
+
for name in ["openai_chat", "alpaca", "dpo", "sharegpt"]:
|
|
71
|
+
print(f" --preset={name}")
|
|
72
|
+
print()
|
|
73
|
+
print("示例:")
|
|
74
|
+
print(f" dt validate {filename} --preset=openai_chat")
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
preset_lower = preset.lower().replace("-", "_")
|
|
78
|
+
if preset_lower not in PRESET_SCHEMAS:
|
|
79
|
+
print(f"错误: 未知的预设 Schema '{preset}'")
|
|
80
|
+
print(f"可用预设: {', '.join(['openai_chat', 'alpaca', 'dpo', 'sharegpt'])}")
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
schema = PRESET_SCHEMAS[preset_lower]()
|
|
84
|
+
|
|
85
|
+
# 加载数据
|
|
86
|
+
try:
|
|
87
|
+
data = load_data(str(filepath))
|
|
88
|
+
except Exception as e:
|
|
89
|
+
print(f"错误: 无法读取文件 - {e}")
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
if not data:
|
|
93
|
+
print("文件为空")
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
total = len(data)
|
|
97
|
+
print(f"验证文件: {filepath.name}")
|
|
98
|
+
print(f"预设 Schema: {preset}")
|
|
99
|
+
print(f"总记录数: {total}")
|
|
100
|
+
print()
|
|
101
|
+
|
|
102
|
+
# 验证
|
|
103
|
+
valid_data = []
|
|
104
|
+
invalid_count = 0
|
|
105
|
+
error_samples = []
|
|
106
|
+
|
|
107
|
+
for i, item in enumerate(data):
|
|
108
|
+
result = schema.validate(item)
|
|
109
|
+
if result.valid:
|
|
110
|
+
valid_data.append(item)
|
|
111
|
+
else:
|
|
112
|
+
invalid_count += 1
|
|
113
|
+
if len(error_samples) < max_errors:
|
|
114
|
+
error_samples.append((i, result))
|
|
115
|
+
|
|
116
|
+
valid_count = len(valid_data)
|
|
117
|
+
valid_ratio = valid_count / total * 100 if total > 0 else 0
|
|
118
|
+
|
|
119
|
+
# 输出结果
|
|
120
|
+
if invalid_count == 0:
|
|
121
|
+
print(f"✅ 全部通过! {valid_count}/{total} 条记录有效 (100%)")
|
|
122
|
+
else:
|
|
123
|
+
print(f"⚠️ 验证结果: {valid_count}/{total} 条有效 ({valid_ratio:.1f}%)")
|
|
124
|
+
print(f" 无效记录: {invalid_count} 条")
|
|
125
|
+
print()
|
|
126
|
+
|
|
127
|
+
# 显示错误示例
|
|
128
|
+
print(f"错误示例 (最多显示 {max_errors} 条):")
|
|
129
|
+
print("-" * 60)
|
|
130
|
+
|
|
131
|
+
for idx, result in error_samples:
|
|
132
|
+
print(f"[第 {idx} 行]")
|
|
133
|
+
for err in result.errors[:3]: # 每条记录最多显示 3 个错误
|
|
134
|
+
print(f" - {err}")
|
|
135
|
+
if len(result.errors) > 3:
|
|
136
|
+
print(f" ... 还有 {len(result.errors) - 3} 个错误")
|
|
137
|
+
print()
|
|
138
|
+
|
|
139
|
+
# 保存有效数据
|
|
140
|
+
if output or filter_invalid:
|
|
141
|
+
output_path = output or str(filepath).replace(
|
|
142
|
+
filepath.suffix, f"_valid{filepath.suffix}"
|
|
143
|
+
)
|
|
144
|
+
save_data(valid_data, output_path)
|
|
145
|
+
print(f"✅ 有效数据已保存: {output_path} ({valid_count} 条)")
|
|
146
|
+
|
|
147
|
+
# 详细模式:显示 Schema 定义
|
|
148
|
+
if verbose:
|
|
149
|
+
print()
|
|
150
|
+
print("Schema 定义:")
|
|
151
|
+
print("-" * 40)
|
|
152
|
+
print(schema)
|