from fastapi import APIRouter, HTTPException, Request from app.services.kitchenowl import kitchenowl from app.services.repository import repo from app.services.store import JsonStore router = APIRouter(prefix="/api/suggestions", tags=["suggestions"]) store = JsonStore() def _bump(counter: dict, key: str, amount: int = 1) -> None: counter[key] = int(counter.get(key, 0)) + amount def _apply_learning(profile: dict, suggestion: dict, approved: bool) -> dict: ingredients = suggestion.get("ingredients") or [] tags = suggestion.get("tags") or [] title = str(suggestion.get("title") or "").strip().lower() ingredient_counter_key = "approved_ingredients" if approved else "rejected_ingredients" tag_counter_key = "approved_tags" if approved else "rejected_tags" title_counter_key = "approved_titles" if approved else "rejected_titles" for ingredient in ingredients: _bump(profile.setdefault(ingredient_counter_key, {}), ingredient) for tag in tags: _bump(profile.setdefault(tag_counter_key, {}), tag) if title: _bump(profile.setdefault(title_counter_key, {}), title) return profile @router.get("") async def list_suggestions(): items = sorted(repo.list_suggestions(), key=lambda item: item.get("updated_at") or item.get("created_at") or "", reverse=True) return {"items": items, "backend": repo.backend} @router.post("/{suggestion_id}/decision") async def decide(suggestion_id: str, request: Request): payload = await request.json() decision = str(payload.get("decision") or "").strip().lower() current = next((item for item in repo.list_suggestions() if str(item.get("id")) == str(suggestion_id)), None) if not current: raise HTTPException(status_code=404, detail="Suggestion not found.") if decision not in {"approve", "reject", "later"}: raise HTTPException(status_code=400, detail="Decision must be approve, reject, or later.") profile = repo.get_profile() kitchenowl_result = None if decision == "approve": profile = _apply_learning(profile, current, approved=True) import_now = bool(payload.get("import_to_kitchenowl", True)) already_linked = str(current.get("status") or "") == "approved" and str(current.get("kitchenowl_status") or "") in {"created", "duplicate", "updated"} if import_now and kitchenowl.configured() and not already_linked: kitchenowl_result = kitchenowl.create_recipe(current.get("payload") or {}) current_status = "approved" elif decision == "reject": profile = _apply_learning(profile, current, approved=False) current_status = "rejected" else: current_status = "saved" repo.save_profile(profile) updated = repo.update_suggestion( suggestion_id, { "status": current_status, "updated_at": store.now(), "decision_at": store.now(), "kitchenowl_status": (kitchenowl_result or {}).get("status") if kitchenowl_result else current.get("kitchenowl_status", "not-imported"), "kitchenowl_result": kitchenowl_result, }, ) return {"status": "ok", "suggestion": updated, "profile": profile, "kitchenowl": kitchenowl_result}