Sarco-Monitor / schemas /user_input.py
Ning311's picture
Update schemas/user_input.py
f3c81c5 verified
"""
用户输入数据模型定义
使用Pydantic进行数据验证
"""
from pydantic import BaseModel, Field
from typing import Optional, List
from enum import Enum
class RiskLevel(str, Enum):
"""风险等级枚举"""
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
class ModelType(str, Enum):
"""模型类型枚举"""
SARCO_I = "sarcoI"
SARCO_II = "sarcoII"
class UserInput(BaseModel):
"""用户输入数据模型"""
# 基本信息 (注意:本系统适用于18-55岁成年人群)
age_years: float = Field(..., ge=16, le=120, description="年龄(岁) - 推荐18-55岁")
race_ethnicity: int = Field(..., ge=0, le=4, description="种族/民族编码(0-4)")
# 身体指标
body_mass_index: float = Field(..., ge=10, le=80, description="体质量指数BMI")
WWI: float = Field(..., ge=3, le=50, description="腰围重量指数")
# NHANES PAQ 原始问卷数据
# 工作相关活动
PAQ605: int = Field(..., ge=1, le=2, description="工作高强度活动(1=是,2=否)")
PAQ610: Optional[int] = Field(0, ge=0, le=7, description="工作高强度活动天数/周")
PAD615: Optional[float] = Field(0, ge=0, le=1440, description="工作高强度活动分钟数/天")
PAQ620: int = Field(..., ge=1, le=2, description="工作中等强度活动(1=是,2=否)")
PAQ625: Optional[int] = Field(0, ge=0, le=7, description="工作中等强度活动天数/周")
PAD630: Optional[float] = Field(0, ge=0, le=1440, description="工作中等强度活动分钟数/天")
# 交通相关活动
PAQ635: int = Field(..., ge=1, le=2, description="步行/骑车通勤(1=是,2=否)")
PAQ640: Optional[int] = Field(0, ge=0, le=7, description="步行/骑车通勤天数/周")
PAD645: Optional[float] = Field(0, ge=0, le=1440, description="步行/骑车通勤分钟数/天")
# 休闲运动活动
PAQ650: int = Field(..., ge=1, le=2, description="休闲高强度活动(1=是,2=否)")
PAQ655: Optional[int] = Field(0, ge=0, le=7, description="休闲高强度活动天数/周")
PAD660: Optional[float] = Field(0, ge=0, le=1440, description="休闲高强度活动分钟数/天")
PAQ665: int = Field(..., ge=1, le=2, description="休闲中等强度活动(1=是,2=否)")
PAQ670: Optional[int] = Field(0, ge=0, le=7, description="休闲中等强度活动天数/周")
PAD675: Optional[float] = Field(0, ge=0, le=1440, description="休闲中等强度活动分钟数/天")
# 久坐行为
PAD680: float = Field(..., ge=0, le=1440, description="每日久坐时间(分钟)")
# 医疗史 (筛查模型必需)
arthritis: Optional[int] = Field(0, ge=0, le=1, description="关节炎史(0=无,1=有)")
diabetes: Optional[int] = Field(0, ge=0, le=1, description="糖尿病史(0=无,1=有)")
# 计算得出的衍生特征 (前端计算后传入)
Activity_Sedentary_Ratio: Optional[float] = Field(None, ge=0, le=100, description="久坐活动比例")
Total_Moderate_Minutes_week: Optional[float] = Field(None, ge=0, le=10080, description="每周中等强度运动时间(分钟)")
Total_Moderate_Equivalent_Minutes: Optional[float] = Field(None, ge=0, le=10080, description="每周中等强度等效运动时间(分钟)")
Avg_Vigorous_Duration_Per_Bout: Optional[float] = Field(None, ge=0, le=1440, description="平均高强度运动时长每次(分钟)")
Vigorous_MET_Ratio: Optional[float] = Field(None, ge=0, le=10, description="高强度运动比例")
Activity_Diversity_Index: Optional[float] = Field(None, ge=0, le=5, description="活动多样性指数(0-5)")
sedentary_minutes: Optional[float] = Field(None, ge=0, le=1440, description="每日久坐时间(分钟,同PAD680)")
class Config:
json_schema_extra = {
"example": {
"age_years": 45,
"race_ethnicity": 2,
"body_mass_index": 28.5,
"WWI": 11.2,
"PAQ605": 2,
"PAQ620": 1,
"PAQ625": 3,
"PAD630": 60,
"PAQ635": 1,
"PAQ640": 5,
"PAD645": 30,
"PAQ650": 1,
"PAQ655": 2,
"PAD660": 45,
"PAQ665": 1,
"PAQ670": 3,
"PAD675": 60,
"PAD680": 480,
"arthritis": 0,
"diabetes": 0,
"Activity_Sedentary_Ratio": 0.6,
"Total_Moderate_Minutes_week": 150,
"Total_Moderate_Equivalent_Minutes": 150,
"Avg_Vigorous_Duration_Per_Bout": 30,
"Vigorous_MET_Ratio": 0.3,
"Activity_Diversity_Index": 3,
"sedentary_minutes": 480
}
}
class ScreeningRequest(BaseModel):
"""筛查请求模型"""
user_data: UserInput
models: List[ModelType] = [ModelType.SARCO_I, ModelType.SARCO_II]
class AdvisoryRequest(BaseModel):
"""建议请求模型"""
user_data: UserInput
risk_types: List[ModelType] = []
num_recommendations: int = Field(default=3, ge=1, le=5, description="建议数量")
language: str = Field(default="zh", description="语言设置 (zh/en)")
class ScreeningResponse(BaseModel):
"""筛查响应模型"""
# 筛查模型结果 (高召回率)
sarcoI_risk: RiskLevel
sarcoI_probability: float
sarcoI_threshold: float
sarcoII_risk: RiskLevel
sarcoII_probability: float
sarcoII_threshold: float
# 建议模型结果 (高精确率)
sarcoI_advisory_risk: Optional[RiskLevel] = None
sarcoI_advisory_probability: Optional[float] = None
sarcoI_advisory_threshold: Optional[float] = None
sarcoII_advisory_risk: Optional[RiskLevel] = None
sarcoII_advisory_probability: Optional[float] = None
sarcoII_advisory_threshold: Optional[float] = None
# 综合结果
overall_risk: RiskLevel
confidence: float
processing_time: float
class RecommendationItem(BaseModel):
"""单个建议项"""
title: str
description: str
priority: str
target_change: Optional[str] = None
expected_impact: Optional[str] = None
class AdvisoryResponse(BaseModel):
"""建议响应模型"""
sarcoI_recommendations: List[RecommendationItem]
sarcoII_recommendations: List[RecommendationItem]
recommendations: Optional[List[RecommendationItem]] = None # 合并的建议列表,用于前端显示
priority_actions: List[str]
target_metrics: dict
processing_time: float
success: bool
fallback_used: bool = False
class ErrorResponse(BaseModel):
"""错误响应模型"""
error: str
detail: str
timestamp: str