from datetime import date from enum import Enum from typing import List, Optional from uuid import UUID from pydantic import BaseModel, Field, root_validator, field_serializer class MealType(str, Enum): BREAKFAST = "breakfast" LUNCH = "lunch" DINNER = "dinner" SNACK = "snack" class ActivityIntensity(str, Enum): LOW = "low" MEDIUM = "medium" HIGH = "high" class GoalType(str, Enum): LOSE_WEIGHT = "lose_weight" MAINTAIN = "maintain" GAIN_WEIGHT = "gain_weight" HEALTH = "health" # Схемы для FoodItem class FoodItemBase(BaseModel): name: str brand: Optional[str] = None description: Optional[str] = None food_type: Optional[str] = None serving_size: Optional[str] = None serving_weight_grams: Optional[float] = None calories: Optional[float] = None protein_grams: Optional[float] = None fat_grams: Optional[float] = None carbs_grams: Optional[float] = None fiber_grams: Optional[float] = None sugar_grams: Optional[float] = None sodium_mg: Optional[float] = None cholesterol_mg: Optional[float] = None ingredients: Optional[str] = None class FoodItemCreate(FoodItemBase): fatsecret_id: Optional[str] = None is_verified: bool = False class FoodItemResponse(FoodItemBase): id: int uuid: str fatsecret_id: Optional[str] = None is_verified: bool created_at: str updated_at: Optional[str] = None class Config: from_attributes = True # Схемы для UserNutritionEntry class UserNutritionEntryBase(BaseModel): entry_date: date meal_type: MealType quantity: float = Field(gt=0) unit: Optional[str] = None notes: Optional[str] = None class UserNutritionEntryCreate(UserNutritionEntryBase): food_item_id: Optional[int] = None custom_food_name: Optional[str] = None calories: Optional[float] = None protein_grams: Optional[float] = None fat_grams: Optional[float] = None carbs_grams: Optional[float] = None @root_validator(skip_on_failure=True) def check_food_info(cls, values): food_item_id = values.get("food_item_id") custom_food_name = values.get("custom_food_name") if food_item_id is None and not custom_food_name: raise ValueError("Either food_item_id or custom_food_name must be provided") return values class UserNutritionEntryResponse(UserNutritionEntryBase): id: int uuid: str user_id: int food_item_id: Optional[int] = None custom_food_name: Optional[str] = None calories: Optional[float] = None protein_grams: Optional[float] = None fat_grams: Optional[float] = None carbs_grams: Optional[float] = None created_at: str updated_at: Optional[str] = None class Config: from_attributes = True # Схемы для WaterIntake class WaterIntakeBase(BaseModel): entry_date: date amount_ml: int = Field(gt=0) notes: Optional[str] = None class WaterIntakeCreate(WaterIntakeBase): pass class WaterIntakeResponse(WaterIntakeBase): id: int uuid: str user_id: int entry_time: str class Config: from_attributes = True # Схемы для UserActivityEntry class UserActivityEntryBase(BaseModel): entry_date: date activity_type: str duration_minutes: int = Field(gt=0) distance_km: Optional[float] = None steps: Optional[int] = None intensity: Optional[ActivityIntensity] = None notes: Optional[str] = None class UserActivityEntryCreate(UserActivityEntryBase): calories_burned: Optional[float] = None class UserActivityEntryResponse(UserActivityEntryBase): id: int uuid: str user_id: int calories_burned: Optional[float] = None created_at: str class Config: from_attributes = True # Схемы для NutritionGoal class NutritionGoalBase(BaseModel): daily_calorie_goal: Optional[int] = None protein_goal_grams: Optional[int] = None fat_goal_grams: Optional[int] = None carbs_goal_grams: Optional[int] = None water_goal_ml: Optional[int] = None activity_goal_minutes: Optional[int] = None weight_goal_kg: Optional[float] = None goal_type: Optional[GoalType] = None class NutritionGoalCreate(NutritionGoalBase): pass class NutritionGoalResponse(NutritionGoalBase): id: int user_id: int created_at: str updated_at: Optional[str] = None class Config: from_attributes = True # Схемы для запросов к FatSecret API class FoodSearchQuery(BaseModel): query: str page_number: int = 0 max_results: int = 10 class FoodDetailsQuery(BaseModel): food_id: str # Схемы для сводных данных class DailyNutritionSummary(BaseModel): date: date total_calories: float = 0 total_protein_grams: float = 0 total_fat_grams: float = 0 total_carbs_grams: float = 0 total_water_ml: int = 0 total_activity_minutes: int = 0 estimated_calories_burned: float = 0 meals: List[UserNutritionEntryResponse] = [] water_entries: List[WaterIntakeResponse] = [] activity_entries: List[UserActivityEntryResponse] = []