Sélection courante + favoris + images servables (sortie prête Hermes)

Deux outils MCP pour qu'Hermes n'ait plus de scripts à écrire :
- hf_next_delivery() : prochaine box RÉELLEMENT sélectionnée (≈4 recettes,
  pas le menu complet) + date/cutoff ; erreur stricte si introuvable
  (jamais de repli propose). Saute les semaines PAUSED via next_delivery.
- hf_favorites() : recettes favorites du compte. Champ is_favorite ajouté
  partout (hf_get_menu inclus).

Endpoints découverts (probe CDP) :
- sélection : GET /gw/my-deliveries/menu -> meals[].selection.quantity>0
- favoris   : GET /gw/cfs/v2/favorites/recipe -> items[].object_id
(GET /gw/v1/carts/{week} renvoie 404 : pas la lecture de sélection.)

Images : URLs recettes CloudFront (502) réécrites vers
img.hellofresh.com/.../hellofresh_s3/... (hellofresh/images.py),
appliqué dans Recipe.summary() -> profite à tous les outils.

README : procédure de ré-auth CDP clarifiée (refresh tokens rotatifs,
backups inutiles, page /login, profil Chrome dédié).

Outils de re-découverte : tools/probe_selection.py, tools/probe_menu_capture.py
This commit is contained in:
jerem
2026-06-18 14:18:40 +02:00
parent 4b1eb9f52c
commit 03e281a810
8 changed files with 489 additions and 10 deletions

View File

@@ -73,6 +73,55 @@ async def hf_account_info() -> dict:
return await anyio.to_thread.run_sync(_impl)
@mcp.tool()
async def hf_next_delivery() -> dict:
"""Prochaine livraison + recettes RÉELLEMENT sélectionnées (prêt à mettre en forme).
Renvoie la semaine, la date de livraison, le cutoff, et les ~4 recettes de la box avec
image servable (URL corrigée), temps de prépa, allergènes, tags, `is_favorite`. Erreur
stricte si la sélection est introuvable — ne propose JAMAIS de recettes non sélectionnées.
"""
def _impl() -> dict:
with api.HelloFreshClient() as client:
acct = client.account_info()
nd = acct.get("next_delivery") or {}
week = nd.get("week")
if not week:
raise RuntimeError("Aucune prochaine livraison (abonnement en pause ?).")
recipes = client.get_current_selection(week) # lève si vide / KO
favs = client.favorite_ids()
hf_filter.annotate(recipes)
for r in recipes:
r.is_favorite = r.id in favs
return {
"week": week,
"delivery_date": nd.get("date"),
"cutoff": nd.get("cutoff"),
"count": len(recipes),
"recipes": [r.summary() for r in recipes],
}
return await anyio.to_thread.run_sync(_impl)
@mcp.tool()
async def hf_favorites() -> dict:
"""Recettes favorites du compte, complètes (image corrigée, allergènes, `is_favorite`).
Lecture seule. Liste vide si aucun favori. Indépendant de la semaine (favoris globaux).
"""
def _impl() -> dict:
with api.HelloFreshClient() as client:
recipes = client.get_favorites()
hf_filter.annotate(recipes)
return {
"count": len(recipes),
"recipes": [r.summary() for r in recipes],
}
return await anyio.to_thread.run_sync(_impl)
@mcp.tool()
async def hf_get_menu(week: str = "") -> dict:
"""Toutes les recettes proposées pour une semaine, chacune annotée.
@@ -84,7 +133,10 @@ async def hf_get_menu(week: str = "") -> dict:
w = week or api.current_week()
with api.HelloFreshClient() as client:
recipes = client.get_menu(w)
favs = client.favorite_ids() # best-effort (set() si indispo)
hf_filter.annotate(recipes)
for r in recipes:
r.is_favorite = r.id in favs
return {
"week": w,
"count": len(recipes),