Public Access
feat(backend): recipe enrichment with side dishes & detailed instructions
- Add SideDish/SideDishIngredient schemas and recipe.side_dishes JSONB column
- Add recipe_enrichment.py service using Ollama LLM to:
- Rewrite vague instructions with specific temps, quantities, timing, sauce breakdowns
- Suggest 1-2 complementary side dishes with ingredients & prep notes
- Wire enrichment into recipe_ingestion.py discovery pipeline
- Add admin trigger endpoint /api/recipes/{id}/enrich for on-demand enrichment
- Migration 0014: Add side_dishes JSONB to recipe table
- Fix schemas/__init__.py imports: restore RecipeBase/Create/Read exports, add datetime/date for PydanticOptional compatibility
- Deployed to docker-willester and migrated to alembic 0014
This commit is contained in:
@@ -13,6 +13,7 @@ from rapidfuzz import fuzz
|
||||
from sqlalchemy.dialects.postgresql import insert as _pg_insert
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.services.recipe_enrichment import RecipeEnrichmentService
|
||||
from app.models import Ingredient, Recipe
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -24,6 +25,9 @@ _MAX_INGREDIENTS = 20
|
||||
class RecipeIngestionService:
|
||||
"""Ingest external recipes into our database."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.enrichment = RecipeEnrichmentService()
|
||||
|
||||
def ingest(
|
||||
self,
|
||||
db: Session,
|
||||
@@ -78,6 +82,21 @@ class RecipeIngestionService:
|
||||
top_signals = [s["value"] for s in analysis_dict.get("positive_signals", [])]
|
||||
discovery_reason = f"Matched queries: {', '.join(queries[:2])}. Signals: {', '.join(top_signals[:2])}."
|
||||
|
||||
# --- Enrich: detailed instructions + side dishes ---
|
||||
enriched = self.enrichment.enrich(ext.name, mapped_ingredients, instructions)
|
||||
final_instructions = enriched.get("instructions") or instructions
|
||||
side_dishes = enriched.get("side_dishes") or []
|
||||
|
||||
# Append side-dish ingredients to the main ingredient list so shopping lists pick them up
|
||||
for side in side_dishes:
|
||||
for sd_ing in side.get("ingredients", []):
|
||||
mapped_ingredients.append({
|
||||
"ingredient_id": None,
|
||||
"name": sd_ing.get("name", ""),
|
||||
"qty": sd_ing.get("qty"),
|
||||
"unit": sd_ing.get("unit", ""),
|
||||
})
|
||||
|
||||
recipe = Recipe(
|
||||
id=_uuid_mod.uuid4(),
|
||||
family_profile_id=family_profile_id,
|
||||
@@ -93,7 +112,8 @@ class RecipeIngestionService:
|
||||
protein_type=ext.protein_type,
|
||||
calories_per_serving=ext.calories_per_serving,
|
||||
ingredients=mapped_ingredients,
|
||||
instructions=instructions,
|
||||
side_dishes=side_dishes,
|
||||
instructions=final_instructions,
|
||||
source_url=ext.source_url,
|
||||
external_source=ext.external_source,
|
||||
external_id=ext.external_id,
|
||||
|
||||
Reference in New Issue
Block a user