UI web d'admin + garde-fou recettes premium (supplément hors abonnement)
- Refus des recettes payantes (chargeSetting) à la sélection, override allow_premium - Recipe.surcharge_cents/is_premium exposés dans summary(); propose() les exclut - hellofresh/webui.py : page d'admin + API JSON montées sur FastMCP (/, /api/*) édition à chaud des excludes et préférences (liked/disliked)
This commit is contained in:
30
server.py
30
server.py
@@ -20,11 +20,15 @@ from mcp.server.fastmcp import FastMCP
|
||||
|
||||
load_dotenv()
|
||||
|
||||
from hellofresh import api, auth, filter as hf_filter # noqa: E402
|
||||
from hellofresh import api, auth, filter as hf_filter, webui # noqa: E402
|
||||
|
||||
PORT = int(os.environ.get("ANTICOCO_PORT", "9200"))
|
||||
mcp = FastMCP("AntiCoco", host="0.0.0.0", port=PORT)
|
||||
|
||||
# Interface web d'admin (édition à chaud des excludes/préférences) sur le même port.
|
||||
# MCP reste servi sur /mcp ; l'UI est sur / (cf. hellofresh/webui.py).
|
||||
webui.register(mcp)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def hf_auth_status() -> dict:
|
||||
@@ -159,21 +163,26 @@ async def hf_propose(week: str = "", count: int = 0) -> dict:
|
||||
recipes = client.get_menu(w)
|
||||
safe = hf_filter.propose(recipes, count=count or None)
|
||||
excluded = [r.summary() for r in recipes if r.contains_excluded]
|
||||
premium = [r.summary() for r in recipes if r.is_premium and not r.contains_excluded]
|
||||
return {
|
||||
"week": w,
|
||||
"proposed": [r.summary() for r in safe],
|
||||
"excluded_for_coco_etc": excluded,
|
||||
"note": "Aucune écriture effectuée. Confirme avec hf_confirm_selection(week, recipe_ids).",
|
||||
"premium_extra_cost": premium,
|
||||
"note": "Aucune écriture effectuée. Les recettes premium (supplément) sont exclues "
|
||||
"de la proposition. Confirme avec hf_confirm_selection(week, recipe_ids).",
|
||||
}
|
||||
|
||||
return await anyio.to_thread.run_sync(_impl)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def hf_confirm_selection(week: str, recipe_ids: list[str], dry_run: bool = False) -> dict:
|
||||
async def hf_confirm_selection(week: str, recipe_ids: list[str], dry_run: bool = False,
|
||||
allow_premium: bool = False) -> dict:
|
||||
"""ÉCRIT la sélection de recettes dans la box de la semaine (après confirmation).
|
||||
|
||||
Garde-fou : refuse toute recette contenant un ingrédient exclu (coco !).
|
||||
Garde-fous : refuse toute recette contenant un ingrédient exclu (coco !) ET toute
|
||||
recette payante hors abonnement (premium, supplément) sauf si `allow_premium=True`.
|
||||
`dry_run=True` : construit et renvoie la requête sans l'envoyer (vérification).
|
||||
"""
|
||||
def _impl() -> dict:
|
||||
@@ -188,6 +197,19 @@ async def hf_confirm_selection(week: str, recipe_ids: list[str], dry_run: bool =
|
||||
"error": "Sélection refusée : recette(s) avec ingrédient exclu (coco ?).",
|
||||
"offending_ids": bad,
|
||||
}
|
||||
premium = [rid for rid in recipe_ids
|
||||
if rid in by_id and by_id[rid].is_premium]
|
||||
if premium and not allow_premium:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Sélection refusée : recette(s) payante(s) hors abonnement (supplément). "
|
||||
"Repasse allow_premium=True pour accepter le surcoût.",
|
||||
"premium_recipes": [
|
||||
{"id": rid, "name": by_id[rid].name,
|
||||
"surcharge_eur": round(by_id[rid].surcharge_cents / 100, 2)}
|
||||
for rid in premium
|
||||
],
|
||||
}
|
||||
unknown = [rid for rid in recipe_ids if rid not in by_id]
|
||||
if unknown:
|
||||
return {"ok": False, "error": "Recette(s) inconnue(s) pour cette semaine.",
|
||||
|
||||
Reference in New Issue
Block a user