Migrate product-data exports to skill scripts
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from product_data_portable import (
|
||||
DEFAULT_REQUEST_ID,
|
||||
DEFAULT_TIMESTAMP_STEP_MS,
|
||||
@@ -9,6 +7,7 @@ from product_data_portable import (
|
||||
emit_success,
|
||||
load_json_payload,
|
||||
normalize_dataset_draft,
|
||||
resolve_portable_path,
|
||||
)
|
||||
|
||||
|
||||
@@ -17,15 +16,21 @@ def main() -> int:
|
||||
payload = load_json_payload()
|
||||
draft_text = str(payload.get("draft_text") or "")
|
||||
if not draft_text and payload.get("draft_path"):
|
||||
draft_text = Path(str(payload["draft_path"])).expanduser().read_text(encoding="utf-8")
|
||||
draft_text = resolve_portable_path(str(payload["draft_path"])).read_text(encoding="utf-8")
|
||||
source_type = str(payload.get("source_type") or "generated")
|
||||
confirmed_plan_id = str(payload.get("confirmed_plan_id") or "").strip()
|
||||
if source_type == "generated" and not confirmed_plan_id:
|
||||
raise ValueError("confirmed_plan_id is required for generated data")
|
||||
result = normalize_dataset_draft(
|
||||
draft_text,
|
||||
batch_id=str(payload.get("batch_id") or DEFAULT_REQUEST_ID),
|
||||
source_type=str(payload.get("source_type") or "generated"),
|
||||
source_type=source_type,
|
||||
base_timestamp=payload.get("base_timestamp"),
|
||||
timestamp_step_ms=int(payload.get("timestamp_step_ms") or DEFAULT_TIMESTAMP_STEP_MS),
|
||||
default_request_id=str(payload.get("default_request_id") or DEFAULT_REQUEST_ID),
|
||||
)
|
||||
if confirmed_plan_id:
|
||||
result["confirmed_plan_id"] = confirmed_plan_id
|
||||
emit_success(result)
|
||||
return 0
|
||||
except Exception as exc: # noqa: BLE001 - CLI 需要把错误稳定转成 JSON
|
||||
|
||||
@@ -9,6 +9,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
@@ -79,7 +80,7 @@ def load_records(payload: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
|
||||
|
||||
def read_records_file(path: str) -> list[dict[str, Any]]:
|
||||
file_path = Path(path).expanduser()
|
||||
file_path = resolve_portable_path(path)
|
||||
text = file_path.read_text(encoding="utf-8")
|
||||
if file_path.suffix.lower() == ".jsonl":
|
||||
records: list[dict[str, Any]] = []
|
||||
@@ -814,40 +815,82 @@ def default_output_path(payload: dict[str, Any]) -> str:
|
||||
output_format = str(payload.get("output_format") or "jsonl")
|
||||
filename = "records.json" if output_format == "json" else "records.jsonl"
|
||||
if isinstance(payload.get("output_path"), str) and payload["output_path"].strip():
|
||||
return payload["output_path"].strip()
|
||||
return str(resolve_portable_path(payload["output_path"].strip()))
|
||||
if isinstance(payload.get("output_dir"), str) and payload["output_dir"].strip():
|
||||
return str(Path(payload["output_dir"]).expanduser() / filename)
|
||||
return str(Path("output") / filename)
|
||||
return str(resolve_portable_path(payload["output_dir"].strip()) / filename)
|
||||
return str(default_output_root() / filename)
|
||||
|
||||
|
||||
def default_table_output_path(payload: dict[str, Any]) -> str:
|
||||
if isinstance(payload.get("output_path"), str) and payload["output_path"].strip():
|
||||
return payload["output_path"].strip()
|
||||
return str(resolve_portable_path(payload["output_path"].strip()))
|
||||
if isinstance(payload.get("output_dir"), str) and payload["output_dir"].strip():
|
||||
return str(Path(payload["output_dir"]).expanduser() / "records.csv")
|
||||
return str(resolve_portable_path(payload["output_dir"].strip()) / "records.csv")
|
||||
if isinstance(payload.get("records_path"), str) and payload["records_path"].strip():
|
||||
return str(Path(payload["records_path"]).expanduser().with_name("records.csv"))
|
||||
return str(Path("output") / "records.csv")
|
||||
return str(resolve_portable_path(payload["records_path"].strip()).with_name("records.csv"))
|
||||
return str(default_output_root() / "records.csv")
|
||||
|
||||
|
||||
def default_training_output_path(payload: dict[str, Any]) -> str:
|
||||
if isinstance(payload.get("output_path"), str) and payload["output_path"].strip():
|
||||
return payload["output_path"].strip()
|
||||
return str(resolve_portable_path(payload["output_path"].strip()))
|
||||
if isinstance(payload.get("output_dir"), str) and payload["output_dir"].strip():
|
||||
return str(Path(payload["output_dir"]).expanduser() / "training.jsonl")
|
||||
return str(resolve_portable_path(payload["output_dir"].strip()) / "training.jsonl")
|
||||
if isinstance(payload.get("records_path"), str) and payload["records_path"].strip():
|
||||
return str(Path(payload["records_path"]).expanduser().with_name("training.jsonl"))
|
||||
return str(Path("output") / "training.jsonl")
|
||||
return str(resolve_portable_path(payload["records_path"].strip()).with_name("training.jsonl"))
|
||||
return str(default_output_root() / "training.jsonl")
|
||||
|
||||
|
||||
def default_planning_eval_output_path(payload: dict[str, Any]) -> str:
|
||||
if isinstance(payload.get("output_path"), str) and payload["output_path"].strip():
|
||||
return payload["output_path"].strip()
|
||||
return str(resolve_portable_path(payload["output_path"].strip()))
|
||||
if isinstance(payload.get("output_dir"), str) and payload["output_dir"].strip():
|
||||
return str(Path(payload["output_dir"]).expanduser() / "eval_planning.csv")
|
||||
return str(resolve_portable_path(payload["output_dir"].strip()) / "eval_planning.csv")
|
||||
if isinstance(payload.get("records_path"), str) and payload["records_path"].strip():
|
||||
return str(Path(payload["records_path"]).expanduser().with_name("eval_planning.csv"))
|
||||
return str(Path("output") / "eval_planning.csv")
|
||||
return str(resolve_portable_path(payload["records_path"].strip()).with_name("eval_planning.csv"))
|
||||
return str(default_output_root() / "eval_planning.csv")
|
||||
|
||||
|
||||
def default_output_root() -> Path:
|
||||
"""返回 portable 脚本默认输出目录。
|
||||
|
||||
在 ZK Data Agent 中,python_exec 的 cwd 是当前会话 scratchpad;
|
||||
通过 PYTHON_EXEC_SCRATCHPAD 可以定位同级 output 目录。离开平台独立
|
||||
运行时,保持原来的相对 output/ 行为。
|
||||
"""
|
||||
|
||||
scratchpad = os.environ.get("PYTHON_EXEC_SCRATCHPAD")
|
||||
if scratchpad:
|
||||
return Path(scratchpad).expanduser().parent / "output"
|
||||
return Path("output")
|
||||
|
||||
|
||||
def resolve_portable_path(path: str) -> Path:
|
||||
"""解析 portable 脚本路径,并兼容平台逻辑路径。
|
||||
|
||||
平台内运行时,把 output/、scratchpad/、input/ 映射到当前会话目录;
|
||||
其他相对路径仍按当前 cwd 解析,便于普通 Python 环境复用。
|
||||
"""
|
||||
|
||||
raw_path = Path(path).expanduser()
|
||||
if raw_path.is_absolute():
|
||||
return raw_path
|
||||
scratchpad = os.environ.get("PYTHON_EXEC_SCRATCHPAD")
|
||||
if not scratchpad:
|
||||
return raw_path
|
||||
session_root = Path(scratchpad).expanduser().parent
|
||||
parts = raw_path.parts
|
||||
if not parts:
|
||||
return raw_path
|
||||
head, *tail = parts
|
||||
tail_path = Path(*tail) if tail else Path()
|
||||
if head in {"output", "outputs"}:
|
||||
return session_root / "output" / tail_path
|
||||
if head in {"scratchpad", "scratch"}:
|
||||
return Path(scratchpad).expanduser() / tail_path
|
||||
if head in {"input", "inputs"}:
|
||||
return session_root / "input" / tail_path
|
||||
return raw_path
|
||||
|
||||
|
||||
def normalize_target_expression(target: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user