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:
155
platform/as_platform/api/models_routes.py
Normal file
155
platform/as_platform/api/models_routes.py
Normal file
@@ -0,0 +1,155 @@
|
||||
"""模型管理 API 路由 — 模块化前缀 /api/v1/models
|
||||
|
||||
本路由将 training/* 功能以模块化路径重新暴露,同时保留旧路径兼容。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated, Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from as_platform.auth.deps import can_submit_action, get_current_user, require_permission
|
||||
from as_platform.db.models import User
|
||||
from as_platform.data.versions import create_snapshot, diff_versions, get_version, list_versions
|
||||
from as_platform.training.service import (
|
||||
TRAINING_ACTIONS,
|
||||
create_training_submission,
|
||||
get_model_registry,
|
||||
get_training_record,
|
||||
list_training_records,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/v1/models", tags=["models"])
|
||||
|
||||
|
||||
class CreateTrainingBody(BaseModel):
|
||||
action: str
|
||||
params: dict[str, Any] = Field(default_factory=dict)
|
||||
note: str | None = None
|
||||
|
||||
|
||||
@router.get("/actions")
|
||||
def api_models_actions(_user: Annotated[User, Depends(require_permission("read:jobs"))]) -> dict[str, Any]:
|
||||
"""可用的训练/评估/晋级操作列表"""
|
||||
from as_platform.audit.queue import ACTION_LABELS
|
||||
|
||||
return {
|
||||
"actions": [
|
||||
{"id": action, "label": ACTION_LABELS.get(action, action)}
|
||||
for action in sorted(TRAINING_ACTIONS)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@router.get("/registry")
|
||||
def api_models_registry(
|
||||
_user: Annotated[User, Depends(require_permission("read:jobs"))],
|
||||
project: str = Query("dms"),
|
||||
task: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""模型注册表"""
|
||||
return get_model_registry(project=project, task=task)
|
||||
|
||||
|
||||
@router.get("/records")
|
||||
def api_models_records(
|
||||
_user: Annotated[User, Depends(require_permission("read:jobs"))],
|
||||
project: str | None = None,
|
||||
kind: str | None = None,
|
||||
status: str | None = None,
|
||||
task: str | None = None,
|
||||
offset: int = Query(0, ge=0),
|
||||
limit: int = Query(20, ge=1, le=100),
|
||||
) -> dict[str, Any]:
|
||||
"""训练/评估记录列表"""
|
||||
return list_training_records(
|
||||
project=project, kind=kind, status=status, task=task, offset=offset, limit=limit
|
||||
)
|
||||
|
||||
|
||||
@router.get("/records/{record_id}")
|
||||
def api_models_record(
|
||||
record_id: str,
|
||||
_user: Annotated[User, Depends(require_permission("read:jobs"))],
|
||||
) -> dict[str, Any]:
|
||||
"""单条训练记录详情"""
|
||||
rec = get_training_record(record_id)
|
||||
if not rec:
|
||||
raise HTTPException(404, "训练记录不存在")
|
||||
return rec
|
||||
|
||||
|
||||
@router.post("/records")
|
||||
def api_models_create_record(
|
||||
body: CreateTrainingBody,
|
||||
user: Annotated[User, Depends(get_current_user)],
|
||||
) -> dict[str, Any]:
|
||||
"""提交训练/评估/晋级申请"""
|
||||
if not can_submit_action(user, body.action):
|
||||
raise HTTPException(403, f"无权提交: {body.action}")
|
||||
try:
|
||||
return create_training_submission(
|
||||
body.action,
|
||||
body.params,
|
||||
submitted_by=user.name,
|
||||
submitted_by_user_id=user.id,
|
||||
note=body.note,
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(400, str(e)) from e
|
||||
|
||||
|
||||
# ── 数据集版本管理 ──
|
||||
|
||||
class CreateSnapshotBody(BaseModel):
|
||||
project: str = "dms"
|
||||
description: str = ""
|
||||
|
||||
|
||||
@router.get("/datasets")
|
||||
def api_list_dataset_versions(
|
||||
_user: Annotated[User, Depends(require_permission("read:jobs"))],
|
||||
project: str = Query("dms"),
|
||||
) -> dict[str, Any]:
|
||||
return {"items": list_versions(project)}
|
||||
|
||||
|
||||
@router.post("/datasets/snapshot")
|
||||
def api_create_snapshot(
|
||||
body: CreateSnapshotBody,
|
||||
user: Annotated[User, Depends(require_permission("write:approval_submit"))],
|
||||
) -> dict[str, Any]:
|
||||
try:
|
||||
result = create_snapshot(body.project, body.description, author=user.name)
|
||||
from as_platform.audit.log_utils import log_op
|
||||
log_op(user_id=user.id, user_name=user.name, category="data", action="create_snapshot",
|
||||
target_type="snapshot", target_id=result.get("version_id"), summary=f"创建快照: {result.get('version_id')} ({body.project})")
|
||||
return result
|
||||
except Exception as e:
|
||||
raise HTTPException(500, str(e)) from e
|
||||
|
||||
|
||||
@router.get("/datasets/{version_id}")
|
||||
def api_get_version(
|
||||
version_id: str,
|
||||
_user: Annotated[User, Depends(require_permission("read:jobs"))],
|
||||
project: str = Query("dms"),
|
||||
) -> dict[str, Any]:
|
||||
v = get_version(project, version_id)
|
||||
if not v:
|
||||
raise HTTPException(404, f"版本 {version_id} 不存在")
|
||||
return v
|
||||
|
||||
|
||||
@router.get("/datasets/{version_id}/diff")
|
||||
def api_diff_versions(
|
||||
version_id: str,
|
||||
_user: Annotated[User, Depends(require_permission("read:jobs"))],
|
||||
compare: str = Query(...),
|
||||
project: str = Query("dms"),
|
||||
) -> dict[str, Any]:
|
||||
result = diff_versions(project, compare, version_id)
|
||||
if "error" in result:
|
||||
raise HTTPException(400, result["error"])
|
||||
return result
|
||||
Reference in New Issue
Block a user