feat: AI price estimation for shopping list with per-item real-time display
- Add get_shopping_price / get_all_shopping_prices API endpoints - AI (Gemini) estimates retail price per natural unit (pack, piece, bunch) instead of always per-kg — avoids absurd totals like €1609 - _calcEstimatedTotal: proper g/ml→package conversion using defQty + regex on unit_label; only 'kg'/'l' labels trigger weight/volume math - Cache key bumped to v2 to invalidate old per-kg cached entries - Suggested quantity cap lowered from 20 to 10 conf/pz - Unit mismatch guard: if totalUsed >> buyCount*5 for unit=conf, use purchase frequency instead of raw consumption rate - JS _buildPricePayload: use smartShoppingItems for qty/unit (not Bring! spec) - JS _cachedPrices: persist in sessionStorage (survives navigation); validated by _qty/_unit metadata so stale totals auto-invalidate - Price display redesigned: right-side column per row (price-col-main + price-col-unit) instead of small inline badge - fetchAllPrices: buttons disabled immediately before guard check; running total uses only current shoppingItems (not Object.values cache) - Background refresh: always silent (removed 90s interaction condition) - visibilitychange: sets _bgCall=true for shopping before refreshCurrentPage - .gitignore: add runtime data files (bring_migrate_ts, shopping_price_cache, anomaly_dismissed, opened_shelf_cache, shopping_name_cache) - Remove bring_catalog.json and bring_migrate_ts.json from tracking
This commit is contained in:
+22
-6
@@ -103,11 +103,13 @@
|
||||
"banner_expired_action_throw": "Habe ich weggeworfen",
|
||||
"banner_expired_action_edit": "Datum korrigieren",
|
||||
"banner_anomaly_action_edit": "Bestand korrigieren",
|
||||
"banner_anomaly_action_dismiss": "Menge ist korrekt", "banner_no_expiry_title": "Ablaufdatum fehlt: {name}",
|
||||
"banner_anomaly_action_dismiss": "Menge ist korrekt",
|
||||
"banner_no_expiry_title": "Ablaufdatum fehlt: {name}",
|
||||
"banner_no_expiry_detail": "Dieses Produkt hat kein Ablaufdatum. Möchten Sie eines hinzufügen oder bestätigen, dass es nicht verfällt?",
|
||||
"banner_no_expiry_action_set": "Ablaufdatum setzen",
|
||||
"banner_no_expiry_action_dismiss": "Läuft nicht ab ✓",
|
||||
"banner_no_expiry_toast_dismissed": "Als 'läuft nicht ab' markiert", "banner_expiring_title": "Bald ablaufend",
|
||||
"banner_no_expiry_toast_dismissed": "Als 'läuft nicht ab' markiert",
|
||||
"banner_expiring_title": "Bald ablaufend",
|
||||
"banner_expiring_today": "Läuft heute ab!",
|
||||
"banner_expiring_tomorrow": "Läuft morgen ab",
|
||||
"banner_expiring_days": "Läuft in {days} Tagen ab",
|
||||
@@ -133,8 +135,7 @@
|
||||
"banner_anomaly_phantom_title": "mehr Bestand als erwartet",
|
||||
"banner_anomaly_phantom_detail": "Bestand zeigt {inv_qty} {unit}, aber laut Buchungen solltest du nur {expected_qty} {unit} haben. Hast du Bestand ohne Buchung hinzugefügt?",
|
||||
"banner_anomaly_untracked_title": "Anfangsbestand nicht als Eingang gebucht",
|
||||
"banner_anomaly_untracked_detail": "Du hast <strong>{inv_qty} {unit}</strong> im Bestand, aber die gebuchten Abgänge übersteigen die Eingänge — der Anfangsbestand wurde wahrscheinlich nie als \"Eingang\" erfasst. Bitte korrigiere die Menge oder trage die fehlenden Eingänge nach."
|
||||
,
|
||||
"banner_anomaly_untracked_detail": "Du hast <strong>{inv_qty} {unit}</strong> im Bestand, aber die gebuchten Abgänge übersteigen die Eingänge — der Anfangsbestand wurde wahrscheinlich nie als \"Eingang\" erfasst. Bitte korrigiere die Menge oder trage die fehlenden Eingänge nach.",
|
||||
"banner_anomaly_ghost_title": "weniger Bestand als erwartet",
|
||||
"banner_anomaly_ghost_detail": "Laut Buchungen solltest du {expected_qty} {unit} von {name} haben, aber der Bestand zeigt nur {inv_qty} {unit}. Hast du etwas ohne Buchung entnommen?",
|
||||
"consumed": "Verbraucht: {n} ({pct}%)",
|
||||
@@ -161,7 +162,8 @@
|
||||
"label_quantity": "📦 Menge",
|
||||
"label_added": "📅 Hinzugefügt",
|
||||
"empty_text": "Keine Produkte hier.<br>Scanne ein Produkt, um es hinzuzufügen!",
|
||||
"empty_db": "Keine Produkte in der Datenbank.<br>Scanne ein Produkt, um loszulegen!"
|
||||
"empty_db": "Keine Produkte in der Datenbank.<br>Scanne ein Produkt, um loszulegen!",
|
||||
"qty_trace": "< 1"
|
||||
},
|
||||
"scan": {
|
||||
"title": "Produkt scannen",
|
||||
@@ -344,7 +346,7 @@
|
||||
"suggestions_title": "💡 KI-Vorschläge",
|
||||
"suggestions_add": "✅ Ausgewählte zu Bring! hinzufügen",
|
||||
"search_prices": "🔍 Alle Preise suchen",
|
||||
"suggest_btn": "🤖 Einkaufsvorschläge",
|
||||
"suggest_btn": "Einkaufsvorschläge",
|
||||
"smart_title": "🧠 Intelligente Vorhersagen",
|
||||
"smart_empty": "Keine Vorhersagen verfügbar.<br>Füge Produkte zur Vorratskammer hinzu, um intelligente Vorhersagen zu erhalten.",
|
||||
"smart_filter_all": "Alle",
|
||||
@@ -416,6 +418,10 @@
|
||||
"savings_offers": "· 🏷️ Du sparst €{amount} mit Angeboten",
|
||||
"searching_progress": "Suche {current}/{total}...",
|
||||
"remove_error": "Fehler beim Entfernen",
|
||||
"btn_fetch_prices": "Preise suchen",
|
||||
"price_total_label": "💰 Geschätzter Gesamtpreis:",
|
||||
"price_loading": "Preise werden gesucht…",
|
||||
"price_not_found": "Preis n/v",
|
||||
"suggest_loading": "Analyse läuft...",
|
||||
"suggest_error": "Fehler bei der Vorschlagserstellung",
|
||||
"priority_high": "Hoch",
|
||||
@@ -508,6 +514,15 @@
|
||||
"email_label": "📧 Bring! E-Mail",
|
||||
"password_label": "🔒 Bring! Passwort"
|
||||
},
|
||||
"price": {
|
||||
"title": "💰 Preisschätzung (KI)",
|
||||
"hint": "Zeigt geschätzte Kosten pro Produkt in der Einkaufsliste mithilfe von KI an.",
|
||||
"enabled_label": "Preisschätzung aktivieren",
|
||||
"country_label": "🌍 Referenzland",
|
||||
"currency_label": "💱 Währung",
|
||||
"update_label": "🔄 Preise aktualisieren alle",
|
||||
"update_suffix": "Monate"
|
||||
},
|
||||
"recipe": {
|
||||
"title": "🍳 Rezept-Einstellungen",
|
||||
"hint": "Konfiguriere die Standardoptionen für die Rezeptgenerierung.",
|
||||
@@ -906,6 +921,7 @@
|
||||
},
|
||||
"meal_plan": {
|
||||
"reset_success": "Wochenplan zurückgesetzt",
|
||||
"not_available": "nicht im Vorrat verfügbar",
|
||||
"suggested_by": "vom Wochenplan vorgeschlagen"
|
||||
},
|
||||
"kiosk_session": {
|
||||
|
||||
+17
-2
@@ -162,7 +162,8 @@
|
||||
"label_quantity": "📦 Quantity",
|
||||
"label_added": "📅 Added",
|
||||
"empty_text": "No products here.<br>Scan a product to add it!",
|
||||
"empty_db": "No products in the database.<br>Scan a product to get started!"
|
||||
"empty_db": "No products in the database.<br>Scan a product to get started!",
|
||||
"qty_trace": "< 1"
|
||||
},
|
||||
"scan": {
|
||||
"title": "Scan Product",
|
||||
@@ -345,7 +346,7 @@
|
||||
"suggestions_title": "💡 AI Suggestions",
|
||||
"suggestions_add": "✅ Add selected to Bring!",
|
||||
"search_prices": "🔍 Search all prices",
|
||||
"suggest_btn": "🤖 Suggest what to buy",
|
||||
"suggest_btn": "Suggest what to buy",
|
||||
"smart_title": "🧠 Smart Predictions",
|
||||
"smart_empty": "No predictions available.<br>Add products to your pantry to receive smart predictions.",
|
||||
"smart_filter_all": "All",
|
||||
@@ -417,6 +418,10 @@
|
||||
"savings_offers": "· 🏷️ You save €{amount} with offers",
|
||||
"searching_progress": "Searching {current}/{total}...",
|
||||
"remove_error": "Removal error",
|
||||
"btn_fetch_prices": "Find prices",
|
||||
"price_total_label": "💰 Estimated total:",
|
||||
"price_loading": "Looking up prices…",
|
||||
"price_not_found": "price n/a",
|
||||
"suggest_loading": "Analyzing...",
|
||||
"suggest_error": "Suggestion generation error",
|
||||
"priority_high": "High",
|
||||
@@ -509,6 +514,15 @@
|
||||
"email_label": "📧 Bring! Email",
|
||||
"password_label": "🔒 Bring! Password"
|
||||
},
|
||||
"price": {
|
||||
"title": "💰 Price Estimation (AI)",
|
||||
"hint": "Show estimated cost per product in the shopping list using AI.",
|
||||
"enabled_label": "Enable price estimation",
|
||||
"country_label": "🌍 Reference country",
|
||||
"currency_label": "💱 Currency",
|
||||
"update_label": "🔄 Refresh prices every",
|
||||
"update_suffix": "months"
|
||||
},
|
||||
"recipe": {
|
||||
"title": "🍳 Recipe Preferences",
|
||||
"hint": "Configure the default options for recipe generation.",
|
||||
@@ -907,6 +921,7 @@
|
||||
},
|
||||
"meal_plan": {
|
||||
"reset_success": "Weekly plan reset",
|
||||
"not_available": "not available in pantry",
|
||||
"suggested_by": "suggested by weekly plan"
|
||||
},
|
||||
"kiosk_session": {
|
||||
|
||||
+18
-3
@@ -162,7 +162,8 @@
|
||||
"label_quantity": "📦 Quantità",
|
||||
"label_added": "📅 Aggiunto",
|
||||
"empty_text": "Nessun prodotto qui.<br>Scansiona un prodotto per aggiungerlo!",
|
||||
"empty_db": "Nessun prodotto nel database.<br>Scansiona un prodotto per iniziare!"
|
||||
"empty_db": "Nessun prodotto nel database.<br>Scansiona un prodotto per iniziare!",
|
||||
"qty_trace": "< 1"
|
||||
},
|
||||
"scan": {
|
||||
"title": "Scansiona Prodotto",
|
||||
@@ -345,7 +346,7 @@
|
||||
"suggestions_title": "💡 Suggerimenti AI",
|
||||
"suggestions_add": "✅ Aggiungi selezionati a Bring!",
|
||||
"search_prices": "🔍 Cerca tutti i prezzi",
|
||||
"suggest_btn": "🤖 Suggerisci cosa comprare",
|
||||
"suggest_btn": "Suggerisci cosa comprare",
|
||||
"smart_title": "🧠 Previsioni intelligenti",
|
||||
"smart_empty": "Nessuna previsione disponibile.<br>Aggiungi prodotti alla dispensa per ricevere previsioni intelligenti.",
|
||||
"smart_filter_all": "Tutti",
|
||||
@@ -417,6 +418,10 @@
|
||||
"savings_offers": "· 🏷️ Risparmi €{amount} con le offerte",
|
||||
"searching_progress": "Cerco {current}/{total}...",
|
||||
"remove_error": "Errore nella rimozione",
|
||||
"btn_fetch_prices": "Cerca i prezzi",
|
||||
"price_total_label": "💰 Spesa stimata:",
|
||||
"price_loading": "Ricerca prezzi…",
|
||||
"price_not_found": "prezzo n/d",
|
||||
"suggest_loading": "Analisi in corso...",
|
||||
"suggest_error": "Errore nella generazione",
|
||||
"priority_high": "Alta",
|
||||
@@ -509,6 +514,15 @@
|
||||
"email_label": "📧 Email Bring!",
|
||||
"password_label": "🔒 Password Bring!"
|
||||
},
|
||||
"price": {
|
||||
"title": "💰 Stima Prezzi (AI)",
|
||||
"hint": "Mostra il costo stimato di ogni prodotto nella lista della spesa usando l'AI.",
|
||||
"enabled_label": "Attiva stima prezzi",
|
||||
"country_label": "🌍 Paese di riferimento",
|
||||
"currency_label": "💱 Valuta",
|
||||
"update_label": "🔄 Aggiorna prezzi ogni",
|
||||
"update_suffix": "mesi"
|
||||
},
|
||||
"recipe": {
|
||||
"title": "🍳 Preferenze Ricette",
|
||||
"hint": "Configura le opzioni predefinite per la generazione delle ricette.",
|
||||
@@ -907,7 +921,8 @@
|
||||
},
|
||||
"meal_plan": {
|
||||
"reset_success": "Piano settimanale ripristinato",
|
||||
"suggested_by": "suggerito dal piano settimanale"
|
||||
"suggested_by": "suggerito dal piano settimanale",
|
||||
"not_available": "non disponibile in dispensa"
|
||||
},
|
||||
"kiosk_session": {
|
||||
"first_item": "Primo prodotto: {name}!",
|
||||
|
||||
Reference in New Issue
Block a user