summaryrefslogtreecommitdiff
path: root/routers/meals.py
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-08 01:58:48 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-08 01:58:48 -0700
commit2e0a94e88c847a5ed8dc6ad5fa49715cd631bdfe (patch)
tree0c27fc5a8d8cbba60e571bb6690a13c0c0060ff4 /routers/meals.py
Initial commit — Commis personal chef app
AI-powered local chef tool: pantry tracking, meal logging, rotating weekly menu generation, and grocery list optimization via Ollama (llama3). FastAPI backend, SQLite, vanilla JS frontend. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'routers/meals.py')
-rw-r--r--routers/meals.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/routers/meals.py b/routers/meals.py
new file mode 100644
index 0000000..99c5243
--- /dev/null
+++ b/routers/meals.py
@@ -0,0 +1,97 @@
+from fastapi import APIRouter, Depends, HTTPException, Query, status
+from sqlalchemy.orm import Session
+from datetime import datetime, timedelta
+from typing import List, Dict, Any
+from collections import defaultdict
+
+from database import get_db
+from models import MealLog, MealIngredient
+from schemas import MealLogCreate, MealLogRead, MealIngredientCreate
+
+router = APIRouter(prefix="/api/meals", tags=["meals"])
+
+
+@router.get("", response_model=List[MealLogRead])
+def list_meals(
+ days: int = Query(30),
+ meal_type: str = Query(None),
+ db: Session = Depends(get_db)
+):
+ """List meal log entries. Optional query params: ?days=30 (default 30, filters entries from last N days), ?meal_type=dinner. Returns entries ordered by eaten_at desc."""
+ cutoff_date = datetime.utcnow() - timedelta(days=days)
+ query = db.query(MealLog).filter(MealLog.eaten_at >= cutoff_date)
+
+ if meal_type:
+ query = query.filter(MealLog.meal_type == meal_type)
+
+ return query.order_by(MealLog.eaten_at.desc()).all()
+
+
+@router.get("/stats", response_model=Dict[str, Any])
+def meal_stats(db: Session = Depends(get_db)):
+ """Return meal frequency stats. Query last 30 days, count occurrences of each meal_name. Return {"meal_frequency": {"Pasta Carbonara": 3, ...}, "total_meals": 15, "by_type": {"dinner": 10, "lunch": 5}}."""
+ cutoff_date = datetime.utcnow() - timedelta(days=30)
+ meals = db.query(MealLog).filter(MealLog.eaten_at >= cutoff_date).all()
+
+ meal_frequency = defaultdict(int)
+ meal_by_type = defaultdict(int)
+
+ for meal in meals:
+ meal_frequency[meal.meal_name] += 1
+ meal_by_type[meal.meal_type] += 1
+
+ return {
+ "meal_frequency": dict(meal_frequency),
+ "total_meals": len(meals),
+ "by_type": dict(meal_by_type)
+ }
+
+
+@router.get("/{id}", response_model=MealLogRead)
+def get_meal(id: int, db: Session = Depends(get_db)):
+ """Get a single meal log entry."""
+ meal = db.query(MealLog).filter(MealLog.id == id).first()
+ if not meal:
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Meal not found")
+ return meal
+
+
+@router.post("", response_model=MealLogRead, status_code=status.HTTP_201_CREATED)
+def create_meal(meal: MealLogCreate, db: Session = Depends(get_db)):
+ """Log a new meal. If ingredients list provided, create MealIngredient records linked to this meal."""
+ # Create the MealLog entry
+ meal_data = meal.model_dump(exclude={"ingredients"})
+ if meal_data["eaten_at"] is None:
+ meal_data["eaten_at"] = datetime.utcnow()
+
+ db_meal = MealLog(**meal_data)
+ db.add(db_meal)
+ db.commit()
+ db.refresh(db_meal)
+
+ # Create MealIngredient entries if provided
+ if meal.ingredients:
+ for ingredient in meal.ingredients:
+ meal_ingredient = MealIngredient(
+ meal_log_id=db_meal.id,
+ ingredient_name=ingredient.ingredient_name,
+ quantity_used=ingredient.quantity_used,
+ unit=ingredient.unit
+ )
+ db.add(meal_ingredient)
+
+ db.commit()
+ db.refresh(db_meal)
+
+ return db_meal
+
+
+@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_meal(id: int, db: Session = Depends(get_db)):
+ """Delete a meal log entry."""
+ meal = db.query(MealLog).filter(MealLog.id == id).first()
+ if not meal:
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Meal not found")
+
+ db.delete(meal)
+ db.commit()