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:
+76
-1
@@ -630,6 +630,17 @@
|
||||
|
||||
<!-- Tab panel: Da comprare -->
|
||||
<div id="tab-panel-acquisto" class="tab-panel-shopping active">
|
||||
<!-- Price summary bar (shown when prices are enabled) -->
|
||||
<div id="shopping-price-bar" style="display:none">
|
||||
<div class="shopping-price-total-row">
|
||||
<span class="price-total-label" data-i18n="shopping.price_total_label">💰 Spesa stimata:</span>
|
||||
<span class="price-total-value" id="price-total-value">–</span>
|
||||
<button class="btn-price-refresh" id="btn-price-refresh" onclick="fetchAllPrices(false)" title="Aggiorna prezzi">🔄</button>
|
||||
</div>
|
||||
<div id="price-loading-bar" style="display:none" class="price-loading-bar">
|
||||
<div class="price-loading-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shopping-current" id="shopping-current" style="display:none">
|
||||
<div class="shopping-section-header">
|
||||
<h3 data-i18n="shopping.section_to_buy">🛍️ Da comprare</h3>
|
||||
@@ -651,11 +662,14 @@
|
||||
</div>
|
||||
<div class="shopping-actions">
|
||||
<button class="btn btn-large btn-accent" onclick="generateSuggestions()" id="btn-suggest" data-i18n="shopping.suggest_btn">
|
||||
🤖 Suggerisci cosa comprare
|
||||
Suggerisci cosa comprare
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="forceSyncBring()" style="margin-top:4px" data-i18n="shopping.force_sync">
|
||||
🔄 Forza sincronizzazione Bring!
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="btn-fetch-prices" onclick="fetchAllPrices(false)" style="margin-top:4px;display:none" data-i18n="shopping.btn_fetch_prices">
|
||||
Cerca i prezzi
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -785,6 +799,67 @@
|
||||
<button class="btn btn-small btn-secondary mt-2" onclick="togglePasswordVisibility('setting-bring-password')">👁️ Mostra/Nascondi</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Price Estimation Settings -->
|
||||
<div class="settings-card" style="margin-top:12px">
|
||||
<h4 data-i18n="settings.price.title">💰 Stima Prezzi (AI)</h4>
|
||||
<p class="settings-hint" data-i18n="settings.price.hint">Mostra il costo stimato di ogni prodotto nella lista della spesa usando l'AI.</p>
|
||||
<div class="form-group">
|
||||
<label class="toggle-row">
|
||||
<span data-i18n="settings.price.enabled_label">Attiva stima prezzi</span>
|
||||
<span class="toggle-switch">
|
||||
<input type="checkbox" id="setting-price-enabled">
|
||||
<span class="toggle-slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="price-settings-sub" style="display:none">
|
||||
<div class="form-group">
|
||||
<label data-i18n="settings.price.country_label">🌍 Paese di riferimento</label>
|
||||
<select id="setting-price-country" class="form-input" onchange="onPriceCountryChange()">
|
||||
<option value="Italia">🇮🇹 Italia</option>
|
||||
<option value="USA">🇺🇸 USA</option>
|
||||
<option value="Germany">🇩🇪 Germania</option>
|
||||
<option value="France">🇫🇷 Francia</option>
|
||||
<option value="Spain">🇪🇸 Spagna</option>
|
||||
<option value="UK">🇬🇧 Regno Unito</option>
|
||||
<option value="Switzerland">🇨🇭 Svizzera</option>
|
||||
<option value="Austria">🇦🇹 Austria</option>
|
||||
<option value="Netherlands">🇳🇱 Olanda</option>
|
||||
<option value="Belgium">🇧🇪 Belgio</option>
|
||||
<option value="Canada">🇨🇦 Canada</option>
|
||||
<option value="Australia">🇦🇺 Australia</option>
|
||||
<option value="Brazil">🇧🇷 Brasile</option>
|
||||
<option value="Japan">🇯🇵 Giappone</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label data-i18n="settings.price.currency_label">💱 Valuta</label>
|
||||
<select id="setting-price-currency" class="form-input">
|
||||
<option value="EUR">€ Euro (EUR)</option>
|
||||
<option value="USD">$ Dollaro USA (USD)</option>
|
||||
<option value="GBP">£ Sterlina (GBP)</option>
|
||||
<option value="CHF">CHF Franco Svizzero</option>
|
||||
<option value="CAD">CA$ Dollaro Canadese</option>
|
||||
<option value="AUD">A$ Dollaro Australiano</option>
|
||||
<option value="BRL">R$ Real Brasiliano</option>
|
||||
<option value="JPY">¥ Yen Giapponese</option>
|
||||
<option value="SEK">kr Corona Svedese</option>
|
||||
<option value="NOK">kr Corona Norvegese</option>
|
||||
<option value="DKK">kr Corona Danese</option>
|
||||
<option value="PLN">zł Zloty Polacco</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label data-i18n="settings.price.update_label">🔄 Aggiorna prezzi ogni</label>
|
||||
<div class="qty-control">
|
||||
<button type="button" class="qty-btn" onclick="adjustQty('setting-price-update-months', -1, 1, 24)">−</button>
|
||||
<input type="number" id="setting-price-update-months" value="3" min="1" max="24" class="qty-input">
|
||||
<button type="button" class="qty-btn" onclick="adjustQty('setting-price-update-months', 1, 1, 24)">+</button>
|
||||
</div>
|
||||
<span class="settings-hint" style="display:inline;margin-left:8px" data-i18n="settings.price.update_suffix">mesi</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Recipe Tab -->
|
||||
<div class="settings-panel" id="tab-recipe">
|
||||
|
||||
Reference in New Issue
Block a user