fix: AI visual barcode fallback fires only once per scanner session

If Gemini cannot identify the product visually, mark _aiFallbackExhausted=true
for the current scanner session so the 5s timer never fires again. The scanner
restarts normally (user can keep trying with the barcode reader) and a persistent
status message is shown: 'AI: product not recognized — try scanning the barcode'.
_aiFallbackExhausted resets to false in stopScanner() so the next camera session
starts fresh.
This commit is contained in:
dadaloop82
2026-05-29 17:43:55 +00:00
parent 98c38f017e
commit b1bcf9e714
6 changed files with 21 additions and 12 deletions
+11 -7
View File
@@ -1944,6 +1944,7 @@ let aiStream = null;
let _scanZoomLevel = 2; // always 2x let _scanZoomLevel = 2; // always 2x
let _torchActive = false; let _torchActive = false;
let _aiFallbackTimer = null; let _aiFallbackTimer = null;
let _aiFallbackExhausted = false; // true after one failed AI visual attempt — reset when scanner is closed
// Apply fixed 2x zoom (hardware if available, CSS fallback) // Apply fixed 2x zoom (hardware if available, CSS fallback)
async function _applyFixedZoom() { async function _applyFixedZoom() {
@@ -2174,17 +2175,19 @@ async function _tryGeminiVisualBarcode() {
showToast(t('error.connection'), 'error'); showToast(t('error.connection'), 'error');
} }
} else { } else {
scanLog('AI visual: product not identified'); scanLog('AI visual: product not identified — exhausted for this session');
_aiFallbackExhausted = true;
showLoading(false); showLoading(false);
showToast(t('scan.ai_fallback_not_found'), 'warning'); _setScanStatus(t('scan.ai_fallback_exhausted'), 'retry', '');
_setScanStatus(t('scan.status_ready'), '', ''); // Restart the scanner so the user can keep trying with the barcode reader,
// Restart scanner so user can try again // but the 5s AI timer will NOT fire again (_aiFallbackExhausted=true).
setTimeout(() => initScanner(), 300); setTimeout(() => initScanner(), 300);
} }
} catch (e) { } catch (e) {
scanLog(`AI visual error: ${e.message}`); scanLog(`AI visual error: ${e.message}`);
_aiFallbackExhausted = true;
showLoading(false); showLoading(false);
showToast(t('error.connection'), 'error'); _setScanStatus(t('scan.ai_fallback_exhausted'), 'retry', '');
setTimeout(() => initScanner(), 300); setTimeout(() => initScanner(), 300);
} finally { } finally {
_aiBarcodeVisualRunning = false; _aiBarcodeVisualRunning = false;
@@ -6615,10 +6618,10 @@ async function initScanner() {
} }
// After 5s without a scan, auto-trigger AI visual identification (if enabled) // After 5s without a scan, auto-trigger AI visual identification (if enabled)
if (_geminiAvailable && getSettings().barcode_ai_fallback) { if (_geminiAvailable && getSettings().barcode_ai_fallback && !_aiFallbackExhausted) {
clearTimeout(_aiFallbackTimer); clearTimeout(_aiFallbackTimer);
_aiFallbackTimer = setTimeout(() => { _aiFallbackTimer = setTimeout(() => {
if (scannerStream) { // still scanning — no barcode found yet if (scannerStream && !_aiFallbackExhausted) { // still scanning — no barcode found yet
scanLog('5s elapsed without barcode — triggering AI visual fallback'); scanLog('5s elapsed without barcode — triggering AI visual fallback');
_tryGeminiVisualBarcode(); _tryGeminiVisualBarcode();
} }
@@ -6948,6 +6951,7 @@ function stopScanner() {
_scanZoomLevel = 2; // always 2x on next start _scanZoomLevel = 2; // always 2x on next start
_torchActive = false; _torchActive = false;
clearTimeout(_aiFallbackTimer); _aiFallbackTimer = null; clearTimeout(_aiFallbackTimer); _aiFallbackTimer = null;
_aiFallbackExhausted = false; // reset so a new scanner session can try again
if (scannerStream) { if (scannerStream) {
scannerStream.getTracks().forEach(t => t.stop()); scannerStream.getTracks().forEach(t => t.stop());
scannerStream = null; scannerStream = null;
+2 -1
View File
@@ -223,7 +223,8 @@
"status_parallel": "Kombinierter Scan aktiv...", "status_parallel": "Kombinierter Scan aktiv...",
"ai_fallback_searching": "KI identifiziert Produkt...", "ai_fallback_searching": "KI identifiziert Produkt...",
"ai_fallback_found": "Produkt von KI erkannt", "ai_fallback_found": "Produkt von KI erkannt",
"ai_fallback_not_found": "KI: Produkt nicht erkannt" "ai_fallback_not_found": "KI: Produkt nicht erkannt",
"ai_fallback_exhausted": "KI: Produkt nicht erkannt — Barcode erneut scannen"
}, },
"action": { "action": {
"title": "Was möchtest du tun?", "title": "Was möchtest du tun?",
+2 -1
View File
@@ -223,7 +223,8 @@
"status_parallel": "Using combined scan methods...", "status_parallel": "Using combined scan methods...",
"ai_fallback_searching": "AI identifying product...", "ai_fallback_searching": "AI identifying product...",
"ai_fallback_found": "Product identified by AI", "ai_fallback_found": "Product identified by AI",
"ai_fallback_not_found": "AI: product not recognized" "ai_fallback_not_found": "AI: product not recognized",
"ai_fallback_exhausted": "AI: product not recognized — try scanning the barcode"
}, },
"action": { "action": {
"title": "What do you want to do?", "title": "What do you want to do?",
+2 -1
View File
@@ -220,7 +220,8 @@
"status_parallel": "Escaneo combinado activo...", "status_parallel": "Escaneo combinado activo...",
"ai_fallback_searching": "Identificación de IA en curso...", "ai_fallback_searching": "Identificación de IA en curso...",
"ai_fallback_found": "Producto identificado por IA", "ai_fallback_found": "Producto identificado por IA",
"ai_fallback_not_found": "IA: producto no reconocido" "ai_fallback_not_found": "IA: producto no reconocido",
"ai_fallback_exhausted": "IA: producto no reconocido — prueba a escanear el código"
}, },
"action": { "action": {
"title": "¿Qué quieres hacer?", "title": "¿Qué quieres hacer?",
+2 -1
View File
@@ -220,7 +220,8 @@
"status_parallel": "Scan combiné actif...", "status_parallel": "Scan combiné actif...",
"ai_fallback_searching": "Identification IA en cours...", "ai_fallback_searching": "Identification IA en cours...",
"ai_fallback_found": "Produit identifié par l'IA", "ai_fallback_found": "Produit identifié par l'IA",
"ai_fallback_not_found": "IA : produit non reconnu" "ai_fallback_not_found": "IA : produit non reconnu",
"ai_fallback_exhausted": "IA : produit non reconnu — réessayez avec le code-barres"
}, },
"action": { "action": {
"title": "Que voulez-vous faire ?", "title": "Que voulez-vous faire ?",
+2 -1
View File
@@ -223,7 +223,8 @@
"status_parallel": "Doppia scansione attiva...", "status_parallel": "Doppia scansione attiva...",
"ai_fallback_searching": "Identificazione AI in corso...", "ai_fallback_searching": "Identificazione AI in corso...",
"ai_fallback_found": "Prodotto identificato dall'AI", "ai_fallback_found": "Prodotto identificato dall'AI",
"ai_fallback_not_found": "AI: prodotto non riconosciuto" "ai_fallback_not_found": "AI: prodotto non riconosciuto",
"ai_fallback_exhausted": "AI: prodotto non riconosciuto — riprova con il barcode"
}, },
"action": { "action": {
"title": "Cosa vuoi fare?", "title": "Cosa vuoi fare?",