Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from datetime import datetime | |
| import sqlmodel | |
| from pydantic import BaseModel, Field | |
| from sqlalchemy import Column | |
| from sqlalchemy.types import JSON | |
| from sqlmodel import SQLModel | |
| from tracker.constants import MealLogSource, MealPattern, MealSlot | |
| class TrackerUser(SQLModel, table=True): | |
| """Dashboard user owning tracker rows.""" | |
| __tablename__ = "tracker_users" | |
| user_id: int | None = sqlmodel.Field(default=None, primary_key=True) | |
| email: str = sqlmodel.Field(unique=True, index=True) | |
| label: str = sqlmodel.Field(default="") | |
| role: str | None = sqlmodel.Field(default=None) | |
| created_at: datetime = sqlmodel.Field(default_factory=datetime.now) | |
| class Exercise(SQLModel, table=True): | |
| """Exercise catalog entry, seeded from wger/exercemus data.""" | |
| __tablename__ = "exercises" | |
| exercise_id: int | None = sqlmodel.Field(primary_key=True) | |
| name: str = sqlmodel.Field(unique=True, index=True) | |
| muscle_group: str = sqlmodel.Field() | |
| equipment: str = sqlmodel.Field() | |
| wger_id: int | None = sqlmodel.Field(index=True) | |
| starting_bodyweight_fraction: float | None = sqlmodel.Field(default=None) | |
| starting_load_kg: float | None = sqlmodel.Field(default=None) | |
| starting_load_reference: str = sqlmodel.Field(default="") | |
| class Program(SQLModel, table=True): | |
| """Named workout program template.""" | |
| __tablename__ = "programs" | |
| program_id: int | None = sqlmodel.Field(primary_key=True) | |
| user_id: int | None = sqlmodel.Field(default=None, index=True) | |
| name: str = sqlmodel.Field(unique=True) | |
| description: str = sqlmodel.Field() | |
| created_at: datetime = sqlmodel.Field(default_factory=datetime.now) | |
| class ProgramExercise(SQLModel, table=True): | |
| """An exercise within a program day, with rep/set targets.""" | |
| __tablename__ = "program_exercises" | |
| program_id: int = sqlmodel.Field(foreign_key="programs.program_id", primary_key=True) | |
| day_label: str = sqlmodel.Field(primary_key=True) | |
| exercise_id: int = sqlmodel.Field(foreign_key="exercises.exercise_id", primary_key=True) | |
| order_index: int = sqlmodel.Field() | |
| target_sets: int = sqlmodel.Field() | |
| target_rep_min: int = sqlmodel.Field() | |
| target_rep_max: int = sqlmodel.Field() | |
| weight_increment_kg: float = sqlmodel.Field() | |
| rest_seconds: int = sqlmodel.Field() | |
| superset_group: int | None = sqlmodel.Field(index=True) | |
| starting_weight_kg: float | None = sqlmodel.Field(default=None) | |
| class WorkoutLog(SQLModel, table=True): | |
| """Per-set workout log entry.""" | |
| __tablename__ = "workout_logs" | |
| log_id: int | None = sqlmodel.Field(primary_key=True) | |
| user_id: int | None = sqlmodel.Field(default=None, index=True) | |
| exercise_id: int = sqlmodel.Field(foreign_key="exercises.exercise_id", index=True) | |
| program_id: int = sqlmodel.Field(foreign_key="programs.program_id") | |
| day_label: str = sqlmodel.Field() | |
| logged_at: datetime = sqlmodel.Field(default_factory=datetime.now, index=True) | |
| set_number: int = sqlmodel.Field() | |
| reps_target: int = sqlmodel.Field() | |
| reps_done: int = sqlmodel.Field() | |
| weight_kg: float = sqlmodel.Field() | |
| completed: bool = sqlmodel.Field() | |
| class BodyWeightLog(SQLModel, table=True): | |
| """Daily body weight measurement.""" | |
| __tablename__ = "body_weight_logs" | |
| log_id: int | None = sqlmodel.Field(primary_key=True) | |
| user_id: int | None = sqlmodel.Field(default=None, index=True) | |
| logged_at: datetime = sqlmodel.Field(default_factory=datetime.now, index=True) | |
| weight_kg: float = sqlmodel.Field() | |
| class RunLog(SQLModel, table=True): | |
| """Running session for a specific program day (same scope as strength WorkoutLog batches).""" | |
| __tablename__ = "run_logs" | |
| run_log_id: int | None = sqlmodel.Field(default=None, primary_key=True) | |
| user_id: int | None = sqlmodel.Field(default=None, index=True) | |
| program_id: int | None = sqlmodel.Field(default=None, foreign_key="programs.program_id", index=True) | |
| day_label: str | None = sqlmodel.Field(default=None, index=True) | |
| logged_at: datetime = sqlmodel.Field(default_factory=datetime.now, index=True) | |
| distance_km: float = sqlmodel.Field() | |
| duration_minutes: float = sqlmodel.Field() | |
| notes: str = sqlmodel.Field(default="") | |
| class PlannedMeal(SQLModel, table=True): | |
| """A planned meal row in tracker.db (recipe id references parser corpus).""" | |
| __tablename__ = "planned_meals" | |
| planned_meal_id: int | None = sqlmodel.Field(default=None, primary_key=True) | |
| user_id: int | None = sqlmodel.Field(default=None, index=True) | |
| plan_date: str = sqlmodel.Field(index=True) | |
| meal_slot: str = sqlmodel.Field(index=True) | |
| recipe_id: int | None = sqlmodel.Field(default=None, index=True) | |
| notes: str = sqlmodel.Field(default="") | |
| planned_add_ins: list[str] = sqlmodel.Field( | |
| default_factory=list, | |
| sa_column=Column(JSON), | |
| ) | |
| class MealLogEntry(SQLModel, table=True): | |
| """Logged meal adherence or manual food entry.""" | |
| __tablename__ = "meal_log_entries" | |
| meal_log_id: int | None = sqlmodel.Field(default=None, primary_key=True) | |
| user_id: int | None = sqlmodel.Field(default=None, index=True) | |
| logged_at: datetime = sqlmodel.Field(default_factory=datetime.now, index=True) | |
| log_date: str = sqlmodel.Field(index=True) | |
| meal_slot: str = sqlmodel.Field(index=True) | |
| description: str = sqlmodel.Field() | |
| kcal: int | None = None | |
| protein_g: float | None = None | |
| recipe_id: int | None = sqlmodel.Field(default=None, index=True) | |
| source: str = sqlmodel.Field() | |
| class RecipeSearchDefaults(BaseModel): | |
| """Default filters for recipe search (agent profile).""" | |
| max_active_minutes: int | None = None | |
| max_total_minutes: int | None = None | |
| min_calories: int | None = None | |
| max_calories: int | None = None | |
| min_protein: float | None = None | |
| search_limit: int | None = None | |
| class AgentProfileYaml(BaseModel): | |
| """Optional fields loaded from agent_profile.yaml (partial).""" | |
| pantry_user_id: int | None = None | |
| meal_pattern: MealPattern | None = None | |
| default_timezone: str | None = None | |
| costco_event_label: str | None = None | |
| costco_duration_minutes: int | None = None | |
| weekly_climbing_sessions_target: int | None = None | |
| calorie_policy: str | None = None | |
| recipe_search_defaults: RecipeSearchDefaults | None = None | |
| raw_addins_defaults: list[str] = Field(default_factory=list) | |
| class ResolvedAgentProfile(BaseModel): | |
| """Merged agent profile for API and MCP (config + YAML).""" | |
| pantry_user_id: int | |
| active_program_id: int | None | |
| meal_pattern: MealPattern | |
| default_timezone: str | |
| costco_event_label: str | |
| costco_duration_minutes: int | |
| weekly_climbing_sessions_target: int | None | |
| calorie_policy: str | |
| recipe_search_defaults: RecipeSearchDefaults | |
| raw_addins_defaults: list[str] | |
| parser_data_dir: str | |
| default_calendar_id: str | |
| chores_calendar_id: str | None | |
| workout_calendar_id: str | None | |
| tracker_app_url: str | |
| class MealPlanUpsertInput(BaseModel): | |
| plan_date: str | |
| meal_slot: MealSlot | |
| recipe_id: int | None = None | |
| notes: str = "" | |
| planned_add_ins: list[str] = Field(default_factory=list) | |
| class MealPlanRow(BaseModel): | |
| planned_meal_id: int | |
| plan_date: str | |
| meal_slot: MealSlot | |
| recipe_id: int | None | |
| notes: str | |
| planned_add_ins: list[str] | |
| class MealLogCreateInput(BaseModel): | |
| log_date: str | |
| meal_slot: MealSlot | |
| description: str | |
| kcal: int | None = None | |
| protein_g: float | None = None | |
| recipe_id: int | None = None | |
| source: MealLogSource | |
| class MealLogRow(BaseModel): | |
| meal_log_id: int | |
| logged_at: datetime | |
| log_date: str | |
| meal_slot: MealSlot | |
| description: str | |
| kcal: int | None | |
| protein_g: float | None | |
| recipe_id: int | None | |
| source: MealLogSource | |