Public Access
Backend:
- Planner config: set_size=21 (was 3), top_k=30 (was 20)
- generate.py: distribute 21 recipes across 7 days × 3 meal types
- meals.py: add POST /items/{id}/approve, /items/{id}/deny
- meals.py: add POST /{plan_id}/generate-item for empty slots
Frontend:
- Dashboard: Approve/Deny buttons on pending meal cards
- Dashboard: Generate button in empty meal slots
- API client: approveItem, denyItem, generateItem methods
Build: TypeScript compiles clean, Python syntax verified.
43 lines
1.6 KiB
Python
43 lines
1.6 KiB
Python
"""Planner constants. Tune here without touching algorithm code."""
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PlannerConfig:
|
||
# Hard constraints
|
||
recency_weeks: int = 4 # constraint #3: no repeat within N weeks
|
||
calorie_tolerance_pct: int = 20 # constraint #4: ±X% of family.calorie_target
|
||
max_total_minutes: int = 45 # constraint #5: prep + cook
|
||
max_meal_cost: float = 30.00 # constraint #6: dollars per meal
|
||
|
||
# Scoring weights (must sum to 1.0)
|
||
w_savings: float = 0.30
|
||
w_coverage: float = 0.25
|
||
w_pantry: float = 0.10
|
||
w_time: float = 0.15
|
||
w_recency: float = 0.20
|
||
|
||
# Time bonus boundaries
|
||
time_ideal_minutes: int = 25 # full bonus at <= this
|
||
time_full_minutes: int = 45 # zero bonus at this; matches max_total_minutes
|
||
|
||
# Recency bonus boundary
|
||
recency_full_weeks: int = 12 # full bonus when last cooked >= this many weeks ago
|
||
|
||
# Set selection
|
||
top_k: int = 20 # how many feasible recipes to enumerate over
|
||
set_size: int = 21 # 21 meals/week (3 per day × 7 days)
|
||
p_protein: float = 0.15 # diversity penalty per shared-protein pair
|
||
p_cuisine: float = 0.10 # diversity penalty per shared-cuisine pair
|
||
|
||
def validate(self) -> None:
|
||
total = self.w_savings + self.w_coverage + self.w_pantry + self.w_time + self.w_recency
|
||
if abs(total - 1.0) > 1e-6:
|
||
raise ValueError(f"weights must sum to 1.0, got {total}")
|
||
|
||
|
||
DEFAULT = PlannerConfig()
|
||
DEFAULT.validate()
|