Initial commit: Happy Up monorepo through Sprint 5.
Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
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
|
||||
Reference in New Issue
Block a user