Initial project scaffold: FastAPI backend + Svelte 5 frontend
Backend (uv): FastAPI app with routers (foods, log, targets, OFF proxy), SQLAlchemy models, Pydantic schemas, migration runner + 0001 initial schema, example pytest suite (7 tests). Frontend (npm): Vite 7 + Svelte 5 runes, lib/ (api, stores, scanner, format) per spec §7, placeholder components, example vitest suite (4 tests). SPEC.md §1: registered uvicorn and Vitest (rule §8.3.3).
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
"""Nutrition math — the ONLY place nutrition is computed (spec §8.1 rule 1).
|
||||
|
||||
Routers never compute nutrition; the frontend never re-derives it.
|
||||
`quantity` is interpreted by context (spec §2.1):
|
||||
- unit_type "weight": quantity is grams; nutrition = (quantity / 100) × per_unit
|
||||
- unit_type "count": quantity is item count; nutrition = quantity × per_unit
|
||||
- meal: quantity is a scaling factor (1.0 = one full meal)
|
||||
"""
|
||||
|
||||
from models import Food
|
||||
|
||||
|
||||
def scale_to_quantity(per_unit: float | None, quantity: float, unit_type: str) -> float:
|
||||
"""Scale a per-unit nutrition value to a logged quantity. Missing values count as 0."""
|
||||
if per_unit is None:
|
||||
return 0.0
|
||||
if unit_type == "weight":
|
||||
return per_unit * quantity / 100.0
|
||||
if unit_type == "count":
|
||||
return per_unit * quantity
|
||||
raise ValueError(f"unknown unit_type: {unit_type!r}")
|
||||
|
||||
|
||||
def entry_calories(food: Food, quantity: float) -> float:
|
||||
"""Calories for a single (non-meal) food at a logged quantity.
|
||||
|
||||
TODO: handle is_meal foods by summing scaled component nutrition
|
||||
(recursively, with cycle detection — spec §2.2).
|
||||
"""
|
||||
return scale_to_quantity(food.calories_per_unit, quantity, food.unit_type)
|
||||
Reference in New Issue
Block a user