workout-tracker / tracker /planner_api.py
ronheichman's picture
Deploy workout tracker
234891d verified
Raw
History Blame Contribute Delete
4.89 kB
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session
from tracker.config import load_config
from tracker.db import get_session
from tracker.food_service import (
append_meal_log,
delete_planned_meal,
list_meal_logs,
list_planned_meals,
upsert_planned_meal,
)
from tracker.models import MealLogCreateInput, MealPlanUpsertInput, MealLogRow, MealPlanRow
from tracker.planner_schemas import (
DailyWeighinResponse,
DeleteEventResponse,
RecipeSearchResponse,
ScheduleEventInput,
ScheduledEvent,
ScheduleWorkoutsInput,
TrackerStateResponse,
)
from tracker.planner_service import (
build_shopping_gap,
build_tracker_state,
create_daily_weighin,
delete_calendar_event,
fetch_calendar_view,
fetch_pantry,
run_schedule_event,
run_schedule_workouts,
search_recipes,
)
from tracker.agent_profile import resolve_agent_profile
router = APIRouter(prefix="/api/planner")
@router.get("/calendar")
def view_calendar(days_ahead: int = 7):
return fetch_calendar_view(days_ahead)
@router.post("/schedule-workouts")
def api_schedule_workouts(
body: ScheduleWorkoutsInput,
session: Session = Depends(get_session),
) -> list[ScheduledEvent]:
cfg = load_config()
data, err = run_schedule_workouts(session, cfg, body)
if err is not None:
raise HTTPException(status_code=404, detail=err)
if data is None:
raise HTTPException(status_code=404, detail="No program found")
return data
@router.post("/schedule-event")
def api_schedule_event(body: ScheduleEventInput) -> ScheduledEvent:
cfg = load_config()
return run_schedule_event(cfg, body)
@router.delete("/calendar/{event_id}")
def api_delete_event(event_id: str) -> DeleteEventResponse:
cfg = load_config()
return delete_calendar_event(cfg, event_id)
@router.post("/daily-weighin")
def api_daily_weighin() -> DailyWeighinResponse:
cfg = load_config()
return create_daily_weighin(cfg)
@router.get("/pantry")
def view_pantry(user_id: int = 5):
cfg = load_config()
return fetch_pantry(cfg, user_id)
@router.get("/recipes/search")
def search_recipes_route(
q: str,
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,
limit: int = 20,
) -> RecipeSearchResponse:
cfg = load_config()
profile = resolve_agent_profile(cfg)
defaults = profile.recipe_search_defaults
eff_max_active = max_active_minutes if max_active_minutes is not None else defaults.max_active_minutes
eff_max_total = max_total_minutes if max_total_minutes is not None else defaults.max_total_minutes
eff_min_cal = min_calories if min_calories is not None else defaults.min_calories
eff_max_cal = max_calories if max_calories is not None else defaults.max_calories
eff_min_prot = min_protein if min_protein is not None else defaults.min_protein
eff_limit = defaults.search_limit if defaults.search_limit is not None else limit
return search_recipes(
cfg,
q,
eff_max_active,
eff_max_total,
eff_min_cal,
eff_max_cal,
eff_min_prot,
eff_limit,
)
@router.get("/tracker-state")
def view_tracker_state(session: Session = Depends(get_session)) -> TrackerStateResponse:
cfg = load_config()
return build_tracker_state(session, cfg)
@router.get("/shopping-list")
def build_shopping_list(
ingredients: str,
user_id: int = 5,
):
cfg = load_config()
return build_shopping_gap(cfg, ingredients, user_id)
@router.get("/meal-plan")
def get_meal_plan_route(
start_date: str,
end_date: str,
session: Session = Depends(get_session),
) -> list[MealPlanRow]:
return list_planned_meals(session, start_date, end_date)
@router.post("/meal-plan")
def post_meal_plan_route(
body: MealPlanUpsertInput,
session: Session = Depends(get_session),
) -> MealPlanRow:
return upsert_planned_meal(session, body)
@router.delete("/meal-plan/{planned_meal_id}")
def delete_meal_plan_route(
planned_meal_id: int,
session: Session = Depends(get_session),
) -> dict[str, str]:
ok = delete_planned_meal(session, planned_meal_id)
if not ok:
raise HTTPException(status_code=404, detail="Planned meal not found")
return {"deleted": str(planned_meal_id)}
@router.get("/meal-logs")
def get_meal_logs_route(
start_date: str,
end_date: str,
session: Session = Depends(get_session),
) -> list[MealLogRow]:
return list_meal_logs(session, start_date, end_date)
@router.post("/meal-logs")
def post_meal_log_route(
body: MealLogCreateInput,
session: Session = Depends(get_session),
) -> MealLogRow:
return append_meal_log(session, body)