feat: 新增外部数据源拉取与 DPO 输出格式支持
- 支持从 PostgreSQL 数据库拉取结构化数据作为训练来源 - 新增 DPO (Direct Preference Optimization) 输出类型 - 支持 chosen/rejected 字段的编辑、校验和发布 - 完善数据预处理切分逻辑和元数据管理 - 移除 OCR 扫描 PDF 功能,保持基础文本解析能力 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Any, Literal
|
||||
from urllib.parse import parse_qs, urlsplit
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
|
||||
@@ -15,6 +16,31 @@ def _config_value(config: dict[str, Any], snake_name: str, camel_name: str, defa
|
||||
|
||||
|
||||
def _validate_process_config(config: dict[str, Any]) -> None:
|
||||
output_type = _config_value(config, "output_type", "outputType", "standard")
|
||||
if output_type not in {"standard", "reasoning", "dpo"}:
|
||||
raise ValueError("output_type must be one of: standard, reasoning, dpo")
|
||||
|
||||
source_mode = _config_value(config, "source_mode", "sourceMode", "local")
|
||||
if source_mode not in {"local", "external"}:
|
||||
raise ValueError("source_mode must be one of: local, external")
|
||||
external_source = _config_value(config, "external_source", "externalSource", None)
|
||||
if external_source is not None:
|
||||
if not isinstance(external_source, dict):
|
||||
raise ValueError("external_source must be an object")
|
||||
if any(
|
||||
key.lower() in {"password", "secret", "token", "api_key"}
|
||||
for key in external_source
|
||||
):
|
||||
raise ValueError("external_source must not persist credentials")
|
||||
external_url = str(external_source.get("url") or "").strip()
|
||||
if external_url:
|
||||
parsed_external_url = urlsplit(external_url)
|
||||
sensitive_query_keys = {"password", "secret", "token", "api_key", "user", "username"}
|
||||
if parsed_external_url.username or parsed_external_url.password or (
|
||||
set(parse_qs(parsed_external_url.query)) & sensitive_query_keys
|
||||
):
|
||||
raise ValueError("external_source URL must not contain credentials")
|
||||
|
||||
chunk_method = _config_value(config, "chunk_method", "chunkMethod", "layout_hybrid")
|
||||
if not isinstance(chunk_method, str) or chunk_method not in {
|
||||
"layout_hybrid",
|
||||
@@ -303,6 +329,9 @@ class ExternalSourceRequest(BaseModel):
|
||||
username: str | None = Field(default=None, max_length=150)
|
||||
password: str | None = Field(default=None, max_length=500)
|
||||
limit: int = Field(default=1000, ge=1, le=100_000)
|
||||
connect_timeout_seconds: int = Field(default=5, ge=1, le=30)
|
||||
statement_timeout_seconds: int = Field(default=30, ge=1, le=300)
|
||||
ssl_mode: Literal["disable", "prefer", "require", "verify-ca", "verify-full"] = "prefer"
|
||||
|
||||
|
||||
class ExternalPullRequest(ExternalSourceRequest):
|
||||
@@ -324,6 +353,8 @@ class ResultUpdate(BaseModel):
|
||||
instruction: str | None = None
|
||||
input: str | None = None
|
||||
output: str | None = None
|
||||
chosen: str | None = None
|
||||
rejected: str | None = None
|
||||
expected_updated_at: str | None = None
|
||||
|
||||
|
||||
@@ -374,7 +405,7 @@ class PublishRequest(BaseModel):
|
||||
dataset_type: Literal["train", "test", "eval", "val", "other"] = "train"
|
||||
storage_type: Literal["local"] = "local"
|
||||
split: DatasetSplit = Field(default_factory=DatasetSplit)
|
||||
format: Literal["alpaca_jsonl", "jsonl"] = "alpaca_jsonl"
|
||||
format: Literal["alpaca_jsonl", "jsonl", "dpo"] = "alpaca_jsonl"
|
||||
description: str = ""
|
||||
|
||||
@field_validator("dataset_name")
|
||||
|
||||
Reference in New Issue
Block a user