chore: release v1.7.12 — banner aperti, fix ricette pz, fix usa-tutto

This commit is contained in:
dadaloop82
2026-05-13 11:40:05 +00:00
parent 34e13075ea
commit 2d70e7a688
11 changed files with 116 additions and 51 deletions
+16 -15
View File
@@ -379,25 +379,26 @@ function estimateOpenedExpiryDaysPHP(string $name, string $category, string $loc
if (preg_match('/\b(pollo|tacchino|maiale|manzo|vitello|agnello)\b/', $n)) return 2;
if (preg_match('/salmone|tonno\s+fresco|pesce(?!\s+in)/', $n)) return 2;
if (preg_match('/\b(passata|pelati|polpa|sugo|salsa\s+di\s+pomodoro)\b/', $n)) return 5;
if (preg_match('/insalata|rucola|spinaci|lattuga|crescione|germogli/', $n)) return 2;
if (preg_match('/insalata|rucola|spinaci|lattuga|crescione|germogli/', $n)) return 4;
if (preg_match('/\b(succo|spremuta)\b/', $n)) return 3;
if (preg_match('/\b(birra|beer)\b/', $n)) return 3;
if (preg_match('/\bvino\b/', $n)) return 5;
if (preg_match('/tonno\s+in\s+scatola|tonno\s+rio|sgombro\s+in/', $n)) return 4;
// Fruit opened/cut in fridge — much shorter than sealed
if (preg_match('/\bavocado\b/', $n)) return 2;
if (preg_match('/\b(banana|banane|fragola|lampone|pesca|albicocca|ciliegia|mango|papaya)\b/', $n)) return 2;
if (preg_match('/\b(mela|pera|nettarina|prugna|kiwi|ananas|uva|melone|anguria)\b/', $n)) return 3;
if (preg_match('/\b(arancia|mandarino|pompelmo|clementina|limone)\b/', $n)) return 3; // cut citrus
// Vegetables opened/cut in fridge
if (preg_match('/\b(zucchina|zucchine|melanzana|pomodor)\b/', $n)) return 3;
if (preg_match('/\b(peperone|peperoni)\b/', $n)) return 3;
if (preg_match('/\b(broccolo|broccoli|cavolfiore|cavolo)\b/', $n)) return 3;
if (preg_match('/\bsedano\b|\bfinocchio\b/', $n)) return 3;
if (preg_match('/\b(cipolla|cipolle|cipollotto|scalogno|porro)\b/', $n)) return 4;
if (preg_match('/\b(carota|carote)\b/', $n)) return 5;
if (preg_match('/\b(patata|patate|tubero)\b/', $n)) return 3; // cooked/cut potato
if (preg_match('/\baglio\b/', $n)) return 10;
// Fruit in fridge (opened pack, not necessarily cut)
if (preg_match('/\bavocado\b/', $n)) return 3;
if (preg_match('/\b(fragola|fragole|lampone|lamponi|mirtillo|mirtilli|mora|more)\b/', $n)) return 4;
if (preg_match('/\b(banana|banane|pesca|pesche|albicocca|albicocche|ciliegia|ciliegie|mango|papaya)\b/', $n)) return 4;
if (preg_match('/\b(mela|mele|pera|pere|nettarina|prugna|kiwi|ananas|uva|melone|anguria)\b/', $n)) return 5;
if (preg_match('/\b(arancia|arance|mandarino|mandarini|pompelmo|clementina|limone|limoni)\b/', $n)) return 7;
// Vegetables in fridge (opened pack)
if (preg_match('/\b(zucchina|zucchine|melanzana|melanzane|pomodor)\b/', $n)) return 5;
if (preg_match('/\b(peperone|peperoni)\b/', $n)) return 5;
if (preg_match('/\b(broccolo|broccoli|cavolfiore|cavolo)\b/', $n)) return 4;
if (preg_match('/\bsedano\b|\bfinocchio\b/', $n)) return 5;
if (preg_match('/\b(cipolla|cipolle|cipollotto|scalogno|porro)\b/', $n)) return 6;
if (preg_match('/\b(carota|carote)\b/', $n)) return 7;
if (preg_match('/\b(patata|patate|tubero)\b/', $n)) return 4;
if (preg_match('/\baglio\b/', $n)) return 14;
// ── G: Fridge condiments — medium shelf-life ─────────────────────────
if (preg_match('/maionese|mayo|mayon/', $n)) return 90;
+24 -5
View File
@@ -2497,7 +2497,7 @@ function prewarmShelfLifeCache(PDO $db, int $limit = 5): array {
*/
function getOpenedShelfLifeDays(string $name, string $category, string $location, bool $vacuumSealed = false, bool $allowAI = true): int {
$cacheFile = __DIR__ . '/../data/opened_shelf_cache.json';
$cacheKey = md5(mb_strtolower($name) . '|' . mb_strtolower($location));
$cacheKey = md5(mb_strtolower($name) . '|' . mb_strtolower($location) . '|v2');
// Static in-memory cache: the file is read only ONCE per PHP request,
// even when this function is called for many items in a loop (e.g. getStats).
@@ -3136,6 +3136,9 @@ function generateRecipe(PDO $db): void {
if ($item['unit'] === 'conf' && !empty($item['package_unit']) && $item['default_quantity'] > 0) {
$line .= " ({$item['default_quantity']}{$item['package_unit']}/conf)";
}
if ($item['unit'] === 'pz') {
$line .= ' [usa PEZZI interi — qty_number in pz, non grammi]';
}
// Add expiry info only for priority groups 1-4
if ($group <= 4 && $item['expiry_date']) {
if ($daysLeft < 0) {
@@ -3414,7 +3417,7 @@ REGOLE:
{$mealPlanRule}1. PRIORITÀ: usa prima gli ingredienti scaduti/in scadenza (⚠️🔴🟠), poi quelli [APERTO], poi il resto.
2. Usa SOLO ingredienti dalla lista + acqua/sale/pepe/olio (sempre disponibili).
3. Quantità MASSIME per $persons persona/e (NON superare mai): pasta/riso asciutto 90g/pers, carne 180g/pers, pesce 200g/pers, legumi secchi 80g/pers (lessi 200g/pers), verdure contorno 200g/pers, formaggio 80g/pers, latte 200ml/pers, farina per dolci 200g/pers. Se un ingrediente rimasto è inferiore a questi limiti, usalo tutto.
4. "qty_number": valore NUMERICO nella STESSA unità della dispensa (g/ml/pz/conf, MAI kg o litri). Per non-dispensa: 0.
4. "qty_number": valore NUMERICO nella STESSA unità della dispensa (g/ml/pz/conf, MAI kg o litri). Per non-dispensa: 0. IMPORTANTE: per ingredienti con unità "pz" scrivi qty_number come numero di PEZZI (es. 2, non 200g).
5. "name": usa ESATTAMENTE il nome dalla lista (il sistema lo usa per scalare l'inventario).
6. Includi nella lista ingredienti TUTTI quelli citati nei passi (tranne acqua/sale/pepe/olio).
7. Language rule: {$recipeLangName} only for all textual fields (`title`, `tags`, `expiry_note`, `ingredients.qty`, `steps`, `nutrition_note`). Keep `meal` unchanged.
@@ -3619,7 +3622,7 @@ PROMPT;
$qtyNum = $recipeVal / 1000;
} elseif ($recipeUnit === 'ml' && $invUnit === 'ml') {
$qtyNum = $recipeVal;
// g/ml → pz (approximate to nearest piece)
// g/ml → pz/conf (approximate to nearest piece)
} elseif ($invUnit === 'pz' || $invUnit === 'conf') {
$defQty = (float)($bestMatch['default_quantity'] ?? 0);
if ($defQty > 0) {
@@ -3627,9 +3630,23 @@ PROMPT;
$qtyNum = $recipeVal / $defQty;
$qtyNum = max(0.25, round($qtyNum * 4) / 4); // round to nearest quarter
} else {
$qtyNum = max(1, round($recipeVal / 100)); // fallback heuristic
// No default_quantity: AI was told to use pieces but sent grams.
// If the original qty_number looks like a piece count (≤ invQty and ≤ 100)
// keep it; otherwise fall back to 1.
$origQtyNum = (float)($ing['qty_number'] ?? 0);
if ($origQtyNum >= 1 && $origQtyNum <= $invQty && $origQtyNum <= 100) {
$qtyNum = $origQtyNum; // already a plausible piece count
} else {
$qtyNum = 1; // safe minimum: 1 piece
}
}
}
} elseif ($invUnit === 'pz' && !$recipeUnit) {
// AI returned qty_number without a parseable unit string.
// If qty_number looks like grams (>> available pz count), clamp to 1.
if ($qtyNum > $invQty || $qtyNum > 100) {
$qtyNum = max(1, round($qtyNum / 100));
}
}
// Sanity check: qty_number should not exceed available
@@ -4061,6 +4078,8 @@ function generateRecipeStream(PDO $db): void {
$line = "- {$item['name']}: {$item['quantity']} {$item['unit']}";
if ($item['unit'] === 'conf' && !empty($item['package_unit']) && $item['default_quantity'] > 0)
$line .= " ({$item['default_quantity']}{$item['package_unit']}/conf)";
if ($item['unit'] === 'pz')
$line .= ' [usa PEZZI interi — qty_number in pz, non grammi]';
// Annotazioni urgenza: solo gruppi 1-3 (riduce token per gruppi 4-6)
if ($group <= 3 && $item['expiry_date']) {
if ($daysLeft < 0) $line .= ' ⚠️SCADUTO';
@@ -4274,7 +4293,7 @@ REGOLE:
{$mealPlanRule}1. PRIORITÀ: usa prima gli ingredienti scaduti/in scadenza (⚠️🔴🟠), poi quelli [APERTO], poi il resto.
2. Usa SOLO ingredienti dalla lista + acqua/sale/pepe/olio (sempre disponibili).
3. Quantità MASSIME per $persons persona/e (NON superare mai): pasta/riso asciutto 90g/pers, carne 180g/pers, pesce 200g/pers, legumi secchi 80g/pers (lessi 200g/pers), verdure contorno 200g/pers, formaggio 80g/pers, latte 200ml/pers, farina per dolci 200g/pers. Se un ingrediente rimasto è inferiore a questi limiti, usalo tutto.
4. "qty_number": valore NUMERICO nella STESSA unità della dispensa (g/ml/pz/conf, MAI kg o litri). Per non-dispensa: 0.
4. "qty_number": valore NUMERICO nella STESSA unità della dispensa (g/ml/pz/conf, MAI kg o litri). Per non-dispensa: 0. IMPORTANTE: per ingredienti con unità "pz" scrivi qty_number come numero di PEZZI (es. 2, non 200g).
5. "name": usa ESATTAMENTE il nome dalla lista (il sistema lo usa per scalare l'inventario).
6. Includi nella lista ingredienti TUTTI quelli citati nei passi (tranne acqua/sale/pepe/olio).
7. Language rule: {$recipeLangName} only for all textual fields (`title`, `tags`, `expiry_note`, `ingredients.qty`, `steps`, `nutrition_note`). Keep `meal` unchanged.