from datetime import date, datetime from enum import Enum from typing import Any from pydantic import BaseModel, Field class LoginType(str, Enum): phone_code = "phone_code" wechat = "wechat" class UserRole(str, Enum): parent = "parent" coach = "coach" org_admin = "org_admin" platform_admin = "platform_admin" class Gender(str, Enum): male = "male" female = "female" unknown = "unknown" class VideoScene(str, Enum): front_posture = "front_posture" side_posture = "side_posture" squat = "squat" balance = "balance" gait = "gait" class TaskType(str, Enum): posture_screening = "posture_screening" movement_scoring = "movement_scoring" reassessment = "reassessment" class TaskStatus(str, Enum): CREATED = "CREATED" QUEUED = "QUEUED" PROCESSING = "PROCESSING" SUCCEEDED = "SUCCEEDED" FAILED = "FAILED" CANCELLED = "CANCELLED" class RiskLevel(str, Enum): low = "low" medium = "medium" high = "high" review_required = "review_required" class PlanStatus(str, Enum): draft = "draft" active = "active" completed = "completed" paused = "paused" class LoginRequest(BaseModel): login_type: LoginType = Field(alias="loginType") credential: str code: str | None = None model_config = {"populate_by_name": True} class User(BaseModel): id: int phone_masked: str = Field(alias="phoneMasked") role: UserRole model_config = {"populate_by_name": True} class ChildCreateRequest(BaseModel): name: str birthday: date gender: Gender = Gender.unknown height: float | None = None weight: float | None = None contraindications: str | None = None class ChildUpdateRequest(ChildCreateRequest): pass class Child(BaseModel): id: int name: str birthday: date age: int height: float | None = None weight: float | None = None status: str = "active" class UploadTokenRequest(BaseModel): child_id: int = Field(alias="childId") file_name: str = Field(alias="fileName") content_type: str = Field(alias="contentType") size: int model_config = {"populate_by_name": True} class VideoCreateRequest(BaseModel): child_id: int = Field(alias="childId") object_key: str = Field(alias="objectKey") scene: VideoScene capture_hint: str | None = Field(default=None, alias="captureHint") model_config = {"populate_by_name": True} class AnalysisTaskCreateRequest(BaseModel): child_id: int = Field(alias="childId") video_id: int = Field(alias="videoId") task_type: TaskType = Field(alias="taskType") model_config = {"populate_by_name": True} class AnalysisTaskWebhook(BaseModel): task_id: int = Field(alias="taskId") status: TaskStatus progress: int | None = None error_code: str | None = Field(default=None, alias="errorCode") result: dict[str, Any] | None = None signature: str | None = None model_config = {"populate_by_name": True} class TrainingPlanCreateRequest(BaseModel): child_id: int = Field(alias="childId") report_id: int | None = Field(default=None, alias="reportId") goal: str cycle_days: int = Field(alias="cycleDays", ge=7) exercise_ids: list[int] | None = Field(default=None, alias="exerciseIds") constraints: dict[str, Any] | None = None model_config = {"populate_by_name": True} class TrainingRecordCreateRequest(BaseModel): exercise_id: int = Field(alias="exerciseId") completed: bool score: int | None = Field(default=None, ge=0, le=100) duration_seconds: int | None = Field(default=None, alias="durationSeconds") note: str | None = None media: list[str] | None = None model_config = {"populate_by_name": True} class ReportMetric(BaseModel): name: str value: float level: str confidence: float class ReportReviewRequest(BaseModel): action: str = Field(description="approve or reject") note: str | None = None