Files
fquiz/api/app/schemas/atp_asset.py
T
chengkai3 0f5b338a93 fix:[FL-99][修复ATP版本上传接口响应模型不匹配导致500错误]
问题:POST /api/v1/atp/assets/{asset_id}/releases/upload 接口声明
response_model=AtpAssetReleaseDetail,但实际返回 {task_id, status} 字典,
导致FastAPI响应验证失败,返回500错误。

解决方案:
1. 新增 AtpAssetReleaseUploadResponse 响应模型,包含 task_id 和 status 字段
2. 更新接口声明使用正确的响应模型
3. 返回类型注解改为 AtpAssetReleaseUploadResponse

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-06-12 23:35:52 +08:00

212 lines
7.2 KiB
Python

from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, Field
AtpAssetStatus = Literal["draft", "enabled", "disabled", "archived"]
AtpAssetReleaseStatus = Literal["draft", "released", "archived"]
AtpAssetRunnerKind = Literal["atp", "egm", "hybrid"]
AtpAssetRunStatus = Literal["pending", "running", "success", "failed"]
AtpAssetEngineMode = Literal["wine", "native"]
class AtpAssetSummary(BaseModel):
id: str
code: str
name: str
description: str
status: AtpAssetStatus
voltage_level: str | None = None
tower_type: str | None = None
scene_type: str | None = None
arrester_config: str | None = None
latest_release_no: int = 0
active_release_no: int | None = None
active_release_id: str | None = None
active_release_tag: str | None = None
release_count: int = 0
run_count: int = 0
last_run_status: AtpAssetRunStatus | None = None
last_run_date: datetime | None = None
create_date: datetime
create_user: str | None = None
update_date: datetime
update_user: str | None = None
class AtpAssetListResponse(BaseModel):
items: list[AtpAssetSummary]
total: int
class AtpAssetDetail(AtpAssetSummary):
pass
class AtpAssetCreateRequest(BaseModel):
code: str = Field(min_length=1, max_length=64)
name: str = Field(min_length=1, max_length=255)
description: str = Field(default="", max_length=8000)
status: AtpAssetStatus = "enabled"
voltage_level: str | None = Field(default=None, max_length=16)
tower_type: str | None = Field(default=None, max_length=64)
scene_type: str | None = Field(default=None, max_length=32)
arrester_config: str | None = Field(default=None, max_length=64)
class AtpAssetUpdateRequest(BaseModel):
name: str | None = Field(default=None, min_length=1, max_length=255)
description: str | None = Field(default=None, max_length=8000)
status: AtpAssetStatus | None = None
voltage_level: str | None = Field(default=None, max_length=16)
tower_type: str | None = Field(default=None, max_length=64)
scene_type: str | None = Field(default=None, max_length=32)
arrester_config: str | None = Field(default=None, max_length=64)
class AtpAssetReleaseSummary(BaseModel):
id: str
asset_id: str
asset_code: str
asset_name: str
release_no: int
release_tag: str | None = None
status: AtpAssetReleaseStatus
voltage_level: str
tower_type: str
scene_type: str
scenario_code: str | None = None
runner_kind: AtpAssetRunnerKind
storage_mount_code: str
storage_root_path: str
entry_file: str | None = None
result_file: str | None = None
egm_subdir: str | None = None
egm_result_file: str | None = None
preprocess_script: str | None = None
postprocess_script: str | None = None
content_hash: str
is_active: bool
create_date: datetime
create_user: str | None = None
update_date: datetime
update_user: str | None = None
class AtpAssetReleaseDetail(AtpAssetReleaseSummary):
manifest_json: dict[str, Any] = Field(default_factory=dict)
validation_json: dict[str, Any] = Field(default_factory=dict)
class AtpAssetReleaseListResponse(BaseModel):
items: list[AtpAssetReleaseSummary]
total: int
class AtpAssetReleaseCreateRequest(BaseModel):
release_tag: str | None = Field(default=None, max_length=64)
status: AtpAssetReleaseStatus = "released"
voltage_level: str = Field(min_length=1, max_length=16)
tower_type: str = Field(min_length=1, max_length=64)
scene_type: str = Field(min_length=1, max_length=32)
scenario_code: str | None = Field(default=None, max_length=64)
runner_kind: AtpAssetRunnerKind = "atp"
storage_mount_code: str = Field(default="main", min_length=1, max_length=64)
storage_root_path: str = Field(min_length=1, max_length=2048)
entry_file: str | None = Field(default=None, max_length=255)
result_file: str | None = Field(default=None, max_length=255)
egm_subdir: str | None = Field(default=None, max_length=255)
egm_result_file: str | None = Field(default=None, max_length=255)
preprocess_script: str | None = Field(default=None, max_length=255)
postprocess_script: str | None = Field(default=None, max_length=255)
class AtpAssetReleaseUpdateRequest(BaseModel):
release_tag: str | None = Field(default=None, max_length=64)
status: AtpAssetReleaseStatus | None = None
voltage_level: str | None = Field(default=None, min_length=1, max_length=16)
tower_type: str | None = Field(default=None, min_length=1, max_length=64)
scene_type: str | None = Field(default=None, min_length=1, max_length=32)
scenario_code: str | None = Field(default=None, max_length=64)
runner_kind: AtpAssetRunnerKind | None = None
storage_mount_code: str | None = Field(default=None, min_length=1, max_length=64)
storage_root_path: str | None = Field(default=None, min_length=1, max_length=2048)
entry_file: str | None = Field(default=None, max_length=255)
result_file: str | None = Field(default=None, max_length=255)
egm_subdir: str | None = Field(default=None, max_length=255)
egm_result_file: str | None = Field(default=None, max_length=255)
preprocess_script: str | None = Field(default=None, max_length=255)
postprocess_script: str | None = Field(default=None, max_length=255)
class AtpAssetFileEntry(BaseModel):
relative_path: str
name: str
is_dir: bool
size: int = 0
mime_type: str | None = None
file_role: str | None = None
class AtpAssetFileListResponse(BaseModel):
release_id: str
storage_mount_code: str
storage_root_path: str
items: list[AtpAssetFileEntry]
total: int
class AtpAssetRunSummary(BaseModel):
id: str
asset_id: str
asset_code: str
asset_name: str
release_id: str
release_no: int
release_tag: str | None = None
status: AtpAssetRunStatus
engine_mode: AtpAssetEngineMode
runner_kind: AtpAssetRunnerKind
task_id: str | None = None
storage_mount_code: str | None = None
storage_root_path: str | None = None
materialized_root_path: str | None = None
engine_command: str | None = None
working_dir: str | None = None
timeout_seconds: int
exit_code: int | None = None
started_at: datetime | None = None
finished_at: datetime | None = None
duration_ms: int | None = None
error_message: str | None = None
stdout_size: int = 0
stderr_size: int = 0
create_date: datetime
create_user: str | None = None
class AtpAssetRunDetail(AtpAssetRunSummary):
stdout_text: str | None = None
stderr_text: str | None = None
output_manifest_json: dict[str, Any] = Field(default_factory=dict)
result_summary_json: dict[str, Any] = Field(default_factory=dict)
class AtpAssetRunListResponse(BaseModel):
items: list[AtpAssetRunSummary]
total: int
class AtpAssetRunRequest(BaseModel):
timeout_seconds: int | None = Field(default=None, ge=1)
extra_args: list[str] = Field(default_factory=list, max_length=32)
environment: dict[str, str] = Field(default_factory=dict, max_length=16)
dry_run: bool = False
class AtpAssetReleaseUploadResponse(BaseModel):
task_id: str
status: str