feat: HSAP platform v2 — modular navigation, quality review, audit log, world model simulation

Major changes:
- New frontend (platform/web/): Vite + React 18 + TypeScript + Tailwind
- 4-module navigation: 数据送标 / 模型管理 / 车队管理 / 系统管理
- Data catalog with charts (DMS/ADAS/Lane 3-tab view)
- Quality review workflow (标注质检): Good/Fine/Bad scoring with auto-advance
- Audit enhancements: batch operations, rejection categories, Feishu notifications
- Operation audit log (操作日志)
- World model simulation studio (仿真工坊)
- Dataset version management with snapshots and diff
- ADAS 7-class dataset integration (138K images organized + compressed)
- User management with Feishu integration and pagination
- CRUD/search/filter on all pages, card layout redesign
- PIL-optimized image overlay rendering
- Auto-snapshot on build, in_review workflow stage
- Removed embedded algorithm code (now in workspace)
This commit is contained in:
2026-06-03 11:40:21 +08:00
parent 7c43b44c57
commit e72bc061c5
5487 changed files with 979207 additions and 6197 deletions

View File

@@ -8,8 +8,29 @@ from urllib.parse import quote_plus
AS_ROOT = Path(__file__).resolve().parent.parent.parent
WORKSPACE = AS_ROOT
def resolve_workspace_root() -> Path | None:
"""外部 workspaceDMS/Lane 大文件Docker 内通常为 /data/workspace。"""
candidates: list[Path] = []
explicit = os.environ.get("AS_WORKSPACE_ROOT", "").strip()
if explicit:
candidates.append(Path(explicit))
candidates.extend((Path("/data/workspace"), AS_ROOT.parent / "workspace"))
for cand in candidates:
try:
resolved = cand.resolve()
except OSError:
continue
if resolved.is_dir() and (resolved / "DMS").is_dir():
return resolved
return None
WORKSPACE_ROOT = resolve_workspace_root()
PLATFORM_DIR = AS_ROOT / "platform"
PLATFORM_WEB = PLATFORM_DIR / "web" / "dist"
# Label Studio 工程构建产物scripts/build_hsap_ls_ui.sh
PLATFORM_WEB = PLATFORM_DIR / "ui-hsap" / "dist"
ALGORITHMS_DIR = AS_ROOT / "algorithms"
DATASETS_DIR = AS_ROOT / "datasets"
ALGORITHMS_REGISTRY = ALGORITHMS_DIR / "registry.yaml"
@@ -59,6 +80,7 @@ FEISHU_REDIRECT_URI = os.environ.get(
)
FRONTEND_URL = os.environ.get("AS_FRONTEND_URL", "http://127.0.0.1:8787")
DEV_AUTH_ENABLED = os.environ.get("AS_DEV_AUTH", "").lower() in ("1", "true", "yes")
FORCE_DEV_AUTH = os.environ.get("AS_FORCE_DEV_AUTH", "").lower() in ("1", "true", "yes")
FEISHU_ADMIN_OPEN_IDS = {
x.strip() for x in os.environ.get("FEISHU_ADMIN_OPEN_IDS", "").split(",") if x.strip()
}
@@ -66,6 +88,71 @@ FEISHU_ADMIN_DEPARTMENT_IDS = {
x.strip() for x in os.environ.get("FEISHU_ADMIN_DEPARTMENT_IDS", "").split(",") if x.strip()
}
# ── 飞书多维表格(内网出站同步)──
FEISHU_BITABLE_APP_TOKEN = os.environ.get("FEISHU_BITABLE_APP_TOKEN", "").strip()
# 表在知识库/wiki 内时:填 wiki 链接里 /wiki/ 后节点 IDHSAP 会调 API 解析为 Basc obj_token
FEISHU_BITABLE_WIKI_NODE_TOKEN = os.environ.get("FEISHU_BITABLE_WIKI_NODE_TOKEN", "").strip()
FEISHU_BITABLE_TABLE_ID = os.environ.get("FEISHU_BITABLE_TABLE_ID", "").strip()
FEISHU_LABELING_CHAT_ID = os.environ.get("FEISHU_LABELING_CHAT_ID", "").strip()
FEISHU_BITABLE_SYNC_ENABLED = os.environ.get("FEISHU_BITABLE_SYNC_ENABLED", "").lower() in (
"1",
"true",
"yes",
)
FEISHU_BITABLE_SYNC_INTERVAL_SEC = max(30, int(os.environ.get("FEISHU_BITABLE_SYNC_INTERVAL_SEC", "120")))
FEISHU_BITABLE_AUTO_INGEST = os.environ.get("FEISHU_BITABLE_AUTO_INGEST", "").lower() in (
"1",
"true",
"yes",
)
FEISHU_BITABLE_WEBHOOK_ENABLED = os.environ.get("FEISHU_BITABLE_WEBHOOK_ENABLED", "").lower() in (
"1",
"true",
"yes",
)
# 中文列名(与 FEISHU_BITABLE_OPS.md 一致,可用环境变量覆盖)
def _field(name: str, default: str) -> str:
return os.environ.get(name, default).strip() or default
FEISHU_BITABLE_FIELDS: dict[str, str] = {
"delivery_id": _field("FEISHU_BITABLE_FIELD_DELIVERY_ID", "批次编号"),
"project": _field("FEISHU_BITABLE_FIELD_PROJECT", "项目"),
"task": _field("FEISHU_BITABLE_FIELD_TASK", "任务"),
"mode": _field("FEISHU_BITABLE_FIELD_MODE", "子模式"),
"batch_name": _field("FEISHU_BITABLE_FIELD_BATCH_NAME", "批次名"),
"data_path": _field("FEISHU_BITABLE_FIELD_DATA_PATH", "数据路径"),
"status": _field("FEISHU_BITABLE_FIELD_STATUS", "状态"),
"candidate_id": _field("FEISHU_BITABLE_FIELD_CANDIDATE_ID", "候选ID"),
"campaign_id": _field("FEISHU_BITABLE_FIELD_CAMPAIGN_ID", "活动ID"),
"inbox_path": _field("FEISHU_BITABLE_FIELD_INBOX_PATH", "Inbox路径"),
"progress": _field("FEISHU_BITABLE_FIELD_PROGRESS", "HSAP进度"),
"hsap_link": _field("FEISHU_BITABLE_FIELD_HSAP_LINK", "HSAP链接"),
"error_message": _field("FEISHU_BITABLE_FIELD_ERROR_MESSAGE", "失败原因"),
"last_sync": _field("FEISHU_BITABLE_FIELD_LAST_SYNC", "最后同步"),
"record_id": _field("FEISHU_BITABLE_FIELD_RECORD_ID", "记录ID"),
}
# HSAP stage → 飞书表状态
FEISHU_STATUS_FROM_STAGE: dict[str, str] = {
"raw_pool": "待送标",
"out_for_labeling": "标注中",
"returned": "待入库",
"ingested": "已入库",
"labeling_submitted": "标注中",
}
# ── 功能开关 ──
# 车道线 catalog 质检统计mask 抽样,较慢);暂时默认关闭
LANE_DATA_VIZ_ENABLED = os.environ.get("AS_LANE_DATA_VIZ", "").lower() in ("1", "true", "yes")
# ── 车队地图 / T-Box ──
FLEET_MAP_ENABLED = os.environ.get("AS_FLEET_MAP_ENABLED", "1").lower() in ("1", "true", "yes")
FLEET_MOCK_SEED = os.environ.get("AS_FLEET_MOCK_SEED", "1").lower() in ("1", "true", "yes")
FLEET_MOCK_SIMULATE = os.environ.get("AS_FLEET_MOCK_SIMULATE", "1").lower() in ("1", "true", "yes")
FLEET_SIM_INTERVAL_SEC = int(os.environ.get("AS_FLEET_SIM_INTERVAL_SEC", "8"))
AMAP_KEY = os.environ.get("AS_AMAP_KEY", "").strip()
# 车队地图瓦片gaode国内默认| osm
MAP_TILE_PROVIDER = os.environ.get("AS_MAP_TILE_PROVIDER", "gaode").strip().lower() or "gaode"
TBOX_INGEST_TOKEN = os.environ.get("AS_TBOX_INGEST_TOKEN", "hsap-demo-tbox-token").strip()