Public Access
feat(meals): suggest complementary sides
This commit is contained in:
@@ -35,6 +35,7 @@ from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.models import FamilyProfile, MealPlan, MealPlanItem, MealType, Recipe
|
||||
from app.security import require_session
|
||||
from app.services.meal_pairings import components_with_suggested_sides
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -257,6 +258,10 @@ def synthesize_plan(
|
||||
raw_picks = _parse_picks(raw or "")
|
||||
valid_recipe_ids = {r["id"] for r in library}
|
||||
picks = _validate_picks(raw_picks, valid_recipe_ids)
|
||||
recipe_by_id = {
|
||||
str(r.id): r
|
||||
for r in db.query(Recipe).filter(Recipe.id.in_([uuid.UUID(rid) for rid in valid_recipe_ids])).all()
|
||||
}
|
||||
logger.info(
|
||||
"LLM plan: prompt=%d chars, raw_picks=%d, valid_picks=%d",
|
||||
len(payload.prompt), len(raw_picks), len(picks),
|
||||
@@ -279,6 +284,10 @@ def synthesize_plan(
|
||||
recipe_id=uuid.UUID(pick.recipe_id),
|
||||
day_of_week=pick.day_of_week,
|
||||
meal_type=MealType(pick.meal_type),
|
||||
components=components_with_suggested_sides(
|
||||
recipe_by_id.get(pick.recipe_id),
|
||||
pick.meal_type,
|
||||
),
|
||||
))
|
||||
db.flush()
|
||||
|
||||
@@ -310,6 +319,10 @@ def synthesize_plan(
|
||||
recipe_id=uuid.UUID(chosen["id"]),
|
||||
day_of_week=day,
|
||||
meal_type=MealType(mt),
|
||||
components=components_with_suggested_sides(
|
||||
recipe_by_id.get(chosen["id"]),
|
||||
mt,
|
||||
),
|
||||
))
|
||||
used_recipe_ids.add(uuid.UUID(chosen["id"]))
|
||||
filled_count += 1
|
||||
|
||||
@@ -30,6 +30,10 @@ admin_router = APIRouter(
|
||||
public_router = APIRouter(prefix="/api/meal-plans", tags=["meal-plans"])
|
||||
|
||||
|
||||
def _components_payload(components: dict | None) -> dict:
|
||||
return dict(components or {})
|
||||
|
||||
|
||||
def _to_response(week_start, plan_id, items: List[MealPlanItem], result: GenerationResult) -> GenerationResponse:
|
||||
item_payloads: List[GenerationItem] = []
|
||||
score_by_recipe = {s.recipe_id: s for s in result.selected}
|
||||
@@ -41,7 +45,7 @@ def _to_response(week_start, plan_id, items: List[MealPlanItem], result: Generat
|
||||
day_of_week=it.day_of_week,
|
||||
estimated_cost=it.estimated_cost or 0,
|
||||
score=scored.score if scored else 0.0,
|
||||
components={k: float(v) for k, v in (scored.components.items() if scored else [])},
|
||||
components=_components_payload(it.components or (scored.components if scored else None)),
|
||||
)
|
||||
)
|
||||
return GenerationResponse(
|
||||
@@ -135,7 +139,7 @@ def get_plan(plan_id: UUID, db: Session = Depends(get_db)) -> GenerationResponse
|
||||
day_of_week=it.day_of_week,
|
||||
estimated_cost=it.estimated_cost or 0,
|
||||
score=it.score or 0.0,
|
||||
components={k: float(v) for k, v in (it.components.items() if it.components else [])},
|
||||
components=_components_payload(it.components),
|
||||
)
|
||||
for it in items
|
||||
],
|
||||
|
||||
@@ -19,6 +19,7 @@ from app.schemas import (
|
||||
from app.security import require_session
|
||||
from app.services import approval as approval_service
|
||||
from app.services.feedback_analyzer import FeedbackAnalyzer
|
||||
from app.services.meal_pairings import components_with_suggested_sides
|
||||
from uuid import UUID
|
||||
from typing import List, Optional
|
||||
from datetime import datetime, timedelta, timezone
|
||||
@@ -683,6 +684,7 @@ def generate_single_item(
|
||||
day_of_week=day_of_week,
|
||||
meal_type=MealType[meal_type.upper()],
|
||||
approval_status=MealPlanItemStatus.pending,
|
||||
components=components_with_suggested_sides(recipe, meal_type),
|
||||
)
|
||||
db.add(new_item)
|
||||
db.commit()
|
||||
@@ -769,6 +771,7 @@ def fill_empty_slots(
|
||||
day_of_week=day,
|
||||
meal_type=MealType[mt.upper()],
|
||||
approval_status=MealPlanItemStatus.pending,
|
||||
components=components_with_suggested_sides(recipe, mt),
|
||||
)
|
||||
db.add(new_item)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user