fix: hide meal-plan banner on chip uncheck; fix recipe variety (variation counter, temp scaling, client-side title tracking)
This commit is contained in:
+11
-2
@@ -1403,6 +1403,7 @@ function generateRecipe(PDO $db): void {
|
|||||||
$dietaryRestrictions = $input['dietary_restrictions'] ?? '';
|
$dietaryRestrictions = $input['dietary_restrictions'] ?? '';
|
||||||
$todayRecipes = $input['today_recipes'] ?? [];
|
$todayRecipes = $input['today_recipes'] ?? [];
|
||||||
$mealPlanType = $input['meal_plan_type'] ?? ''; // e.g. 'pasta', 'pesce', 'legumi', ...
|
$mealPlanType = $input['meal_plan_type'] ?? ''; // e.g. 'pasta', 'pesce', 'legumi', ...
|
||||||
|
$variation = max(0, intval($input['variation'] ?? 0)); // 0=first attempt, 1+=re-generation
|
||||||
|
|
||||||
// Fetch all inventory items with expiry info
|
// Fetch all inventory items with expiry info
|
||||||
$stmt = $db->query("
|
$stmt = $db->query("
|
||||||
@@ -1665,10 +1666,18 @@ function generateRecipe(PDO $db): void {
|
|||||||
$weekList = implode(', ', array_map(function($t) { return '"' . $t . '"'; }, array_values($weekOnly)));
|
$weekList = implode(', ', array_map(function($t) { return '"' . $t . '"'; }, array_values($weekOnly)));
|
||||||
$varietyText .= "\n\nRICETTE DEGLI ULTIMI 7 GIORNI:\n{$weekList}\nCerca di variare rispetto a queste ricette recenti: evita piatti troppo simili o con gli stessi ingredienti principali. Alterna pasta, riso, zuppe, carne, pesce, verdure, piatti freddi, ecc.";
|
$varietyText .= "\n\nRICETTE DEGLI ULTIMI 7 GIORNI:\n{$weekList}\nCerca di variare rispetto a queste ricette recenti: evita piatti troppo simili o con gli stessi ingredienti principali. Alterna pasta, riso, zuppe, carne, pesce, verdure, piatti freddi, ecc.";
|
||||||
}
|
}
|
||||||
|
// If this is a re-generation, stress the need for a truly different recipe
|
||||||
|
$regenText = '';
|
||||||
|
if ($variation > 0) {
|
||||||
|
$regenText = "\n\n🔁 RIGENERAZIONE #{$variation}: L'utente ha già visto e scartato le ricette precedenti. " .
|
||||||
|
"Devi proporre qualcosa di COMPLETAMENTE DIVERSO: stile di cucina diverso, ingrediente principale diverso, " .
|
||||||
|
"tecnica di cottura diversa, piatto di un'altra tradizione culinaria o di un'altra categoria. " .
|
||||||
|
"Non basta cambiare il nome della stessa idea. Sorprendi! Sii creativo!";
|
||||||
|
}
|
||||||
|
|
||||||
$prompt = <<<PROMPT
|
$prompt = <<<PROMPT
|
||||||
Sei un nutrizionista e chef italiano esperto. Genera UNA ricetta per $mealLabel per $persons persona/e usando PRINCIPALMENTE gli ingredienti disponibili nella dispensa dell'utente.
|
Sei un nutrizionista e chef italiano esperto. Genera UNA ricetta per $mealLabel per $persons persona/e usando PRINCIPALMENTE gli ingredienti disponibili nella dispensa dell'utente.
|
||||||
{$extraRulesText}{$appliancesText}{$dietaryText}{$mealPlanText}{$varietyText}{$mustUseText}
|
{$extraRulesText}{$appliancesText}{$dietaryText}{$mealPlanText}{$varietyText}{$regenText}{$mustUseText}
|
||||||
|
|
||||||
REGOLE IMPORTANTI:
|
REGOLE IMPORTANTI:
|
||||||
{$mealPlanRule}1. ORDINE DI PRIORITÀ INGREDIENTI (dal più urgente al meno urgente) — gli ingredienti nella lista sono già ordinati per priorità:
|
{$mealPlanRule}1. ORDINE DI PRIORITÀ INGREDIENTI (dal più urgente al meno urgente) — gli ingredienti nella lista sono già ordinati per priorità:
|
||||||
@@ -1724,7 +1733,7 @@ PROMPT;
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
'generationConfig' => [
|
'generationConfig' => [
|
||||||
'temperature' => 0.7,
|
'temperature' => min(1.4, 0.7 + $variation * 0.25),
|
||||||
'maxOutputTokens' => 2048
|
'maxOutputTokens' => 2048
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|||||||
+19
-2
@@ -6092,6 +6092,8 @@ function viewArchivedRecipe(idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _cachedRecipe = null;
|
let _cachedRecipe = null;
|
||||||
|
let _generatedTodayTitles = []; // client-side list, robust vs race conditions
|
||||||
|
let _recipeVariationCount = {}; // { 'pranzo': 0, 'cena': 1, ... }
|
||||||
|
|
||||||
function openRecipeDialog() {
|
function openRecipeDialog() {
|
||||||
const meal = getMealType();
|
const meal = getMealType();
|
||||||
@@ -6980,6 +6982,14 @@ function updateRecipeMealTitle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Show/hide the meal-plan badge hint + top banner in the recipe dialog. */
|
/** Show/hide the meal-plan badge hint + top banner in the recipe dialog. */
|
||||||
|
function onMealPlanChipChange(cb) {
|
||||||
|
const show = cb.checked;
|
||||||
|
const banner = document.getElementById('recipe-mealplan-banner');
|
||||||
|
const hint = document.getElementById('recipe-mealplan-hint');
|
||||||
|
if (banner) banner.style.display = show ? 'flex' : 'none';
|
||||||
|
if (hint) hint.style.display = show ? 'flex' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
function _renderMealPlanHint(mealSlot) {
|
function _renderMealPlanHint(mealSlot) {
|
||||||
const el = document.getElementById('recipe-mealplan-hint');
|
const el = document.getElementById('recipe-mealplan-hint');
|
||||||
const banner = document.getElementById('recipe-mealplan-banner');
|
const banner = document.getElementById('recipe-mealplan-banner');
|
||||||
@@ -7022,6 +7032,9 @@ function _renderMealPlanHint(mealSlot) {
|
|||||||
|
|
||||||
function regenerateRecipe() {
|
function regenerateRecipe() {
|
||||||
_cachedRecipe = null;
|
_cachedRecipe = null;
|
||||||
|
const meal = getMealType();
|
||||||
|
// increment variation counter for this meal slot
|
||||||
|
_recipeVariationCount[meal] = (_recipeVariationCount[meal] || 0) + 1;
|
||||||
document.getElementById('recipe-result').style.display = 'none';
|
document.getElementById('recipe-result').style.display = 'none';
|
||||||
document.getElementById('recipe-loading').style.display = 'none';
|
document.getElementById('recipe-loading').style.display = 'none';
|
||||||
const meal = getMealType();
|
const meal = getMealType();
|
||||||
@@ -7078,8 +7091,9 @@ async function generateRecipe() {
|
|||||||
options,
|
options,
|
||||||
appliances: settings.appliances || [],
|
appliances: settings.appliances || [],
|
||||||
dietary_restrictions: settings.dietary_restrictions || '',
|
dietary_restrictions: settings.dietary_restrictions || '',
|
||||||
today_recipes: await getTodayRecipeTitles(),
|
today_recipes: [...new Set([...await getTodayRecipeTitles(), ..._generatedTodayTitles])],
|
||||||
meal_plan_type: mealPlanType,
|
meal_plan_type: mealPlanType,
|
||||||
|
variation: _recipeVariationCount[meal] || 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
@@ -7096,8 +7110,11 @@ async function generateRecipe() {
|
|||||||
const r = result.recipe;
|
const r = result.recipe;
|
||||||
renderRecipe(r);
|
renderRecipe(r);
|
||||||
|
|
||||||
|
// Track title client-side immediately (before DB save completes)
|
||||||
|
if (r.title) _generatedTodayTitles.push(r.title);
|
||||||
|
|
||||||
// Save to archive
|
// Save to archive
|
||||||
saveRecipeToArchive(r);
|
await saveRecipeToArchive(r);
|
||||||
|
|
||||||
// Cache the recipe for this meal type (in-memory only)
|
// Cache the recipe for this meal type (in-memory only)
|
||||||
_cachedRecipe = { meal, recipe: r };
|
_cachedRecipe = { meal, recipe: r };
|
||||||
|
|||||||
@@ -968,3 +968,12 @@
|
|||||||
[2026-04-04 14:30:02] OK — 11 items cached
|
[2026-04-04 14:30:02] OK — 11 items cached
|
||||||
[2026-04-04 14:35:02] OK — 11 items cached
|
[2026-04-04 14:35:02] OK — 11 items cached
|
||||||
[2026-04-04 14:40:01] OK — 11 items cached
|
[2026-04-04 14:40:01] OK — 11 items cached
|
||||||
|
[2026-04-04 14:45:02] OK — 11 items cached
|
||||||
|
[2026-04-04 14:50:02] OK — 11 items cached
|
||||||
|
[2026-04-04 14:55:01] OK — 11 items cached
|
||||||
|
[2026-04-04 15:00:02] OK — 11 items cached
|
||||||
|
[2026-04-04 15:05:02] OK — 11 items cached
|
||||||
|
[2026-04-04 15:10:02] OK — 11 items cached
|
||||||
|
[2026-04-04 15:15:02] OK — 11 items cached
|
||||||
|
[2026-04-04 15:20:01] OK — 11 items cached
|
||||||
|
[2026-04-04 15:25:02] OK — 11 items cached
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
{"success":true,"items":[{"product_id":151,"name":"Arance Tarocco","brand":"","category":"frutta","unit":"pz","current_qty":0,"default_qty":0,"package_unit":"","pct_left":0,"use_count":9,"buy_count":2,"daily_rate":0.55,"uses_per_month":13.6,"days_since_last_use":2,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (9x)"],"score":135,"on_bring":true,"locations":""},{"product_id":70,"name":"Latte Parzialmente Scremato Uht","brand":"Latteria","category":"bevande","unit":"conf","current_qty":0,"default_qty":500,"package_unit":"ml","pct_left":0,"use_count":13,"buy_count":3,"daily_rate":6.74,"uses_per_month":15.6,"days_since_last_use":9,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (13x)"],"score":135,"on_bring":true,"locations":""},{"product_id":129,"name":"Latte di Montagna","brand":"Mila","category":"en:dairies","unit":"conf","current_qty":0,"default_qty":1000,"package_unit":"ml","pct_left":0,"use_count":9,"buy_count":3,"daily_rate":0.2,"uses_per_month":13.6,"days_since_last_use":1,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (9x)"],"score":135,"on_bring":true,"locations":""},{"product_id":47,"name":"Lenticchie","brand":"Primia","category":"en:plant-based-foods-and-beverages","unit":"g","current_qty":0,"default_qty":400,"package_unit":"","pct_left":0,"use_count":5,"buy_count":3,"daily_rate":35.87,"uses_per_month":6,"days_since_last_use":0,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (5x)"],"score":130,"on_bring":true,"locations":""},{"product_id":115,"name":"Aglio rosso","brand":"Duoccio","category":"condimenti","unit":"pz","current_qty":0,"default_qty":0,"package_unit":"","pct_left":0,"use_count":2,"buy_count":2,"daily_rate":0.14,"uses_per_month":2.7,"days_since_last_use":15,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":true,"locations":""},{"product_id":152,"name":"Muesli Frutta Secca","brand":"Crownfield","category":"altro","unit":"g","current_qty":0,"default_qty":750,"package_unit":"","pct_left":0,"use_count":4,"buy_count":2,"daily_rate":34,"uses_per_month":6.9,"days_since_last_use":9,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":false,"locations":""},{"product_id":3,"name":"Cracker integrali","brand":"Barilla,Mulino Bianco","category":"en:snacks","unit":"conf","current_qty":2,"default_qty":25,"package_unit":"g","pct_left":12,"use_count":6,"buy_count":1,"daily_rate":0.56,"uses_per_month":7.2,"days_since_last_use":6,"days_left":4,"expiry_date":"2026-04-28","days_to_expiry":23,"is_opened":true,"urgency":"high","reasons":["Quasi finito (12%)"],"score":90,"on_bring":true,"locations":"dispensa"},{"product_id":132,"name":"Noci sgusciate","brand":"Fruttbella","category":"conserve","unit":"g","current_qty":60,"default_qty":200,"package_unit":"","pct_left":30,"use_count":4,"buy_count":1,"daily_rate":7.04,"uses_per_month":6,"days_since_last_use":0,"days_left":9,"expiry_date":"2026-04-29","days_to_expiry":24,"is_opened":true,"urgency":"medium","reasons":["Finisce tra ~9gg"],"score":50,"on_bring":true,"locations":"dispensa"},{"product_id":69,"name":"Cipolla Dorata","brand":"","category":"verdura","unit":"pz","current_qty":4,"default_qty":0,"package_unit":"","pct_left":44,"use_count":12,"buy_count":1,"daily_rate":0.32,"uses_per_month":14.4,"days_since_last_use":0,"days_left":12,"expiry_date":"2026-04-13","days_to_expiry":8,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~12gg"],"score":40,"on_bring":true,"locations":"frigo"},{"product_id":154,"name":"Mela Rossa","brand":"","category":"frutta","unit":"pz","current_qty":7,"default_qty":1,"package_unit":"","pct_left":32,"use_count":5,"buy_count":1,"daily_rate":0.87,"uses_per_month":8.7,"days_since_last_use":0,"days_left":8,"expiry_date":"2026-04-15","days_to_expiry":10,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~8gg"],"score":35,"on_bring":false,"locations":"frigo"},{"product_id":136,"name":"Biscotti Pastefrolle","brand":"Balocco","category":"snack","unit":"g","current_qty":350,"default_qty":700,"package_unit":"","pct_left":67,"use_count":4,"buy_count":2,"daily_rate":35.22,"uses_per_month":6,"days_since_last_use":0,"days_left":10,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~10gg"],"score":25,"on_bring":false,"locations":"dispensa"}],"cached_at":"2026-04-04T14:40:01+00:00","cached_ts":1775313601}
|
{"success":true,"items":[{"product_id":151,"name":"Arance Tarocco","brand":"","category":"frutta","unit":"pz","current_qty":0,"default_qty":0,"package_unit":"","pct_left":0,"use_count":9,"buy_count":2,"daily_rate":0.55,"uses_per_month":13.6,"days_since_last_use":2,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (9x)"],"score":135,"on_bring":true,"locations":""},{"product_id":70,"name":"Latte Parzialmente Scremato Uht","brand":"Latteria","category":"bevande","unit":"conf","current_qty":0,"default_qty":500,"package_unit":"ml","pct_left":0,"use_count":13,"buy_count":3,"daily_rate":6.73,"uses_per_month":15.5,"days_since_last_use":9,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (13x)"],"score":135,"on_bring":true,"locations":""},{"product_id":129,"name":"Latte di Montagna","brand":"Mila","category":"en:dairies","unit":"conf","current_qty":0,"default_qty":1000,"package_unit":"ml","pct_left":0,"use_count":9,"buy_count":3,"daily_rate":0.2,"uses_per_month":13.6,"days_since_last_use":1,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (9x)"],"score":135,"on_bring":true,"locations":""},{"product_id":47,"name":"Lenticchie","brand":"Primia","category":"en:plant-based-foods-and-beverages","unit":"g","current_qty":0,"default_qty":400,"package_unit":"","pct_left":0,"use_count":5,"buy_count":3,"daily_rate":35.83,"uses_per_month":6,"days_since_last_use":0,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (5x)"],"score":130,"on_bring":true,"locations":""},{"product_id":115,"name":"Aglio rosso","brand":"Duoccio","category":"condimenti","unit":"pz","current_qty":0,"default_qty":0,"package_unit":"","pct_left":0,"use_count":2,"buy_count":2,"daily_rate":0.14,"uses_per_month":2.7,"days_since_last_use":15,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":true,"locations":""},{"product_id":152,"name":"Muesli Frutta Secca","brand":"Crownfield","category":"altro","unit":"g","current_qty":0,"default_qty":750,"package_unit":"","pct_left":0,"use_count":4,"buy_count":2,"daily_rate":33.94,"uses_per_month":6.9,"days_since_last_use":9,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":false,"locations":""},{"product_id":3,"name":"Cracker integrali","brand":"Barilla,Mulino Bianco","category":"en:snacks","unit":"conf","current_qty":2,"default_qty":25,"package_unit":"g","pct_left":12,"use_count":6,"buy_count":1,"daily_rate":0.56,"uses_per_month":7.1,"days_since_last_use":6,"days_left":4,"expiry_date":"2026-04-28","days_to_expiry":23,"is_opened":true,"urgency":"high","reasons":["Quasi finito (12%)"],"score":90,"on_bring":true,"locations":"dispensa"},{"product_id":132,"name":"Noci sgusciate","brand":"Fruttbella","category":"conserve","unit":"g","current_qty":60,"default_qty":200,"package_unit":"","pct_left":30,"use_count":4,"buy_count":1,"daily_rate":7.03,"uses_per_month":6,"days_since_last_use":0,"days_left":9,"expiry_date":"2026-04-29","days_to_expiry":24,"is_opened":true,"urgency":"medium","reasons":["Finisce tra ~9gg"],"score":50,"on_bring":true,"locations":"dispensa"},{"product_id":69,"name":"Cipolla Dorata","brand":"","category":"verdura","unit":"pz","current_qty":4,"default_qty":0,"package_unit":"","pct_left":44,"use_count":12,"buy_count":1,"daily_rate":0.32,"uses_per_month":14.3,"days_since_last_use":0,"days_left":12,"expiry_date":"2026-04-13","days_to_expiry":8,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~12gg"],"score":40,"on_bring":true,"locations":"frigo"},{"product_id":154,"name":"Mela Rossa","brand":"","category":"frutta","unit":"pz","current_qty":7,"default_qty":1,"package_unit":"","pct_left":32,"use_count":5,"buy_count":1,"daily_rate":0.87,"uses_per_month":8.7,"days_since_last_use":0,"days_left":8,"expiry_date":"2026-04-15","days_to_expiry":10,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~8gg"],"score":35,"on_bring":false,"locations":"frigo"},{"product_id":136,"name":"Biscotti Pastefrolle","brand":"Balocco","category":"snack","unit":"g","current_qty":350,"default_qty":700,"package_unit":"","pct_left":67,"use_count":4,"buy_count":2,"daily_rate":35.16,"uses_per_month":6,"days_since_last_use":0,"days_left":10,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~10gg"],"score":25,"on_bring":false,"locations":"dispensa"}],"cached_at":"2026-04-04T15:25:02+00:00","cached_ts":1775316302}
|
||||||
+1
-1
@@ -1008,7 +1008,7 @@
|
|||||||
<div class="form-group" style="text-align:left">
|
<div class="form-group" style="text-align:left">
|
||||||
<label>🎯 Tipo di pasto</label>
|
<label>🎯 Tipo di pasto</label>
|
||||||
<div class="recipe-options-grid">
|
<div class="recipe-options-grid">
|
||||||
<label class="recipe-option-chip recipe-opt-mealplan-chip" id="recipe-opt-mealplan-wrap" style="display:none"><input type="checkbox" id="recipe-opt-mealplan" checked> <span id="recipe-opt-mealplan-label"></span></label>
|
<label class="recipe-option-chip recipe-opt-mealplan-chip" id="recipe-opt-mealplan-wrap" style="display:none"><input type="checkbox" id="recipe-opt-mealplan" checked onchange="onMealPlanChipChange(this)"> <span id="recipe-opt-mealplan-label"></span></label>
|
||||||
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-veloce"> ⚡ Pasto Veloce</label>
|
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-veloce"> ⚡ Pasto Veloce</label>
|
||||||
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-pocafame"> 🥗 Poca Fame</label>
|
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-pocafame"> 🥗 Poca Fame</label>
|
||||||
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-scadenze"> ⏰ Priorità Scadenze</label>
|
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-scadenze"> ⏰ Priorità Scadenze</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user