feat: Unified Ingest SDK for DMS/ADAS promote, cuboid export and 3D fit
Replace subprocess build with promote_batch SDK, add ADAS cuboid export/fit/validate pipeline, stage normalization, and offline unit tests wired into smoke_labeling_api. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
126
platform/as_platform/data/promote/runner.py
Normal file
126
platform/as_platform/data/promote/runner.py
Normal file
@@ -0,0 +1,126 @@
|
||||
"""Unified pack promote entrypoint."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from as_platform.data.batch import read_meta, write_meta
|
||||
from as_platform.data.catalog_cache import invalidate_catalog_cache
|
||||
from as_platform.data.core import load_wf, proj_root
|
||||
from as_platform.data.promote.base import PromoteContext, PromoteResult
|
||||
from as_platform.data.promote.registry import get_promote_adapter
|
||||
from as_platform.db.engine import session_scope
|
||||
from as_platform.db.models import LabelingCampaign
|
||||
from as_platform.jobs.runner import _auto_snapshot
|
||||
from as_platform.labeling.annotate import resolve_campaign_batch_dir
|
||||
|
||||
|
||||
def _resolve_batch_dir(
|
||||
project: str,
|
||||
task: str,
|
||||
batch: str,
|
||||
*,
|
||||
location: str = "inbox",
|
||||
) -> Path:
|
||||
wf = load_wf()
|
||||
root = proj_root(wf, project)
|
||||
if location == "inbox":
|
||||
if project == "adas":
|
||||
return (root / "inbox" / task / batch).resolve()
|
||||
return (root / "inbox" / task / batch).resolve()
|
||||
raise ValueError(f"unsupported location: {location}")
|
||||
|
||||
|
||||
def _update_campaign_ingested(project: str, task: str, batch: str) -> None:
|
||||
try:
|
||||
with session_scope() as db:
|
||||
camp = (
|
||||
db.query(LabelingCampaign)
|
||||
.filter(
|
||||
LabelingCampaign.project == project,
|
||||
LabelingCampaign.task == task,
|
||||
LabelingCampaign.batch == batch,
|
||||
)
|
||||
.order_by(LabelingCampaign.created_at.desc())
|
||||
.first()
|
||||
)
|
||||
if camp:
|
||||
camp.status = "ingested"
|
||||
db.flush()
|
||||
try:
|
||||
batch_dir = resolve_campaign_batch_dir(camp)
|
||||
meta = read_meta(batch_dir) or {}
|
||||
meta["stage"] = "ingested"
|
||||
meta["pipeline_version"] = 2
|
||||
write_meta(batch_dir, meta)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def promote_batch(
|
||||
project: str,
|
||||
*,
|
||||
task: str,
|
||||
batch: str | None = None,
|
||||
pack: str | None = None,
|
||||
batch_dir: Path | str | None = None,
|
||||
dry_run: bool = False,
|
||||
skip_validate: bool = False,
|
||||
allow_partial_3d: bool = False,
|
||||
refresh: bool = True,
|
||||
all_sources: bool = False,
|
||||
extra: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Promote inbox batch into training pack (SDK entry)."""
|
||||
wf = load_wf()
|
||||
pcfg = wf["projects"][project]
|
||||
pack_name = pack or pcfg.get("base_pack")
|
||||
if not pack_name:
|
||||
raise ValueError(f"project {project} missing pack")
|
||||
if not task:
|
||||
raise ValueError("task required")
|
||||
if all_sources:
|
||||
raise ValueError("all_sources promote not yet in SDK; use CLI ingest_incremental")
|
||||
if not batch:
|
||||
raise ValueError("batch required")
|
||||
|
||||
root = proj_root(wf, project)
|
||||
bdir = Path(batch_dir).resolve() if batch_dir else _resolve_batch_dir(project, task, batch)
|
||||
if not bdir.is_dir():
|
||||
raise ValueError(f"batch_dir not found: {bdir}")
|
||||
|
||||
adapter = get_promote_adapter(project)
|
||||
ctx = PromoteContext(
|
||||
project=project,
|
||||
task=task,
|
||||
batch=batch,
|
||||
pack=pack_name,
|
||||
batch_dir=bdir,
|
||||
project_root=root,
|
||||
dry_run=dry_run,
|
||||
skip_validate=skip_validate,
|
||||
allow_partial_3d=allow_partial_3d,
|
||||
refresh=refresh,
|
||||
extra=extra or {},
|
||||
)
|
||||
|
||||
val_errors = adapter.validate(ctx)
|
||||
if val_errors:
|
||||
raise ValueError("; ".join(val_errors))
|
||||
|
||||
result: PromoteResult = adapter.promote(ctx)
|
||||
if not result.ok:
|
||||
raise ValueError(result.warnings[0] if result.warnings else "promote failed")
|
||||
|
||||
if not dry_run:
|
||||
_update_campaign_ingested(project, task, batch)
|
||||
invalidate_catalog_cache()
|
||||
if project == "dms":
|
||||
_auto_snapshot("dms", task=task)
|
||||
|
||||
out = result.to_dict()
|
||||
out["stdout"] = __import__("json").dumps(out, ensure_ascii=False)
|
||||
out["stderr"] = ""
|
||||
return out
|
||||
Reference in New Issue
Block a user