From 0529c885d31126311b3940d23ab8dd8701d7ffd8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Nov 2025 23:36:47 +0000 Subject: [PATCH] fix: Improve AI price digit recognition to avoid 1.99/9.99 confusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem:** AI was misreading prices: "1,99 €" detected as "9,99 €" with 90% confidence. This is a critical OCR error where similar-looking digits (1, 7, 8, 9) are confused. The model google/gemini-2.5-flash-lite made basic digit recognition mistakes. **Root Cause:** - AI vision models can confuse visually similar digits - No specific instructions in prompt to verify digit accuracy - No validation that detected price matches text context - Model may be too lightweight for reliable OCR **Solution: Three-Part Fix** 1. **Enhanced Prompt with Digit Verification** (ai_schema.py:145-149) - Added "CRITICAL - Read digits carefully" section - Explicit warning: "1,99 €" is NOT "9,99 €" - Instructions to double-check digits 1, 7, 8, 9 (visually similar) - Context check: Small prices (< 5€) are common - Verify price makes sense for product type 2. **More Examples in Prompt** (ai_schema.py:152-153) - Added: "1,99 €" -> 1.99 (NOT 9.99) - Added: "0,99 €" -> 0.99 (NOT 9.99) - Reinforces correct parsing of small prices 3. **Price Extraction Logging** (ai_service.py:349-355) - Extract ALL prices from text with regex: \d+[,\.]\d{2}\s*€ - Log first 10 prices found: ["1,99 €", "2,99 €", ...] - Allows debugging: Is correct price in text? - Logs warning if NO prices found in text 4. **Debug Logs to INFO** (ai_service.py:347, 361) - Changed logger.debug → logger.info for text/prompt preview - Now visible in production logs for diagnosis **Expected Improvement:** - AI should now pay closer attention to digit shapes - Lower confidence (0.5-0.7) if digits are unclear - Better accuracy for small prices (0,99 - 4,99) - Logs will show if problem is in text extraction or AI vision **Testing:** After restart, logs will show: ``` INFO - Cleaned text preview: 'Lutin de Noël 1,99 € Ajouter...' INFO - Prices found in text: ['1,99 €', '2,99 €'] INFO - AI Response: {"price": 1.99, "price_confidence": 0.85} ``` If AI still returns wrong price but text has correct price, then model is insufficient and should be upgraded to: - google/gemini-2.0-flash-exp - anthropic/claude-3-haiku - openai/gpt-4o-mini --- app/ai_schema.py | 10 ++++++++++ app/services/ai_service.py | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/ai_schema.py b/app/ai_schema.py index a3a67dc..65621d1 100644 --- a/app/ai_schema.py +++ b/app/ai_schema.py @@ -141,11 +141,21 @@ EXTRACTION_PROMPT_TEMPLATE = """Extract product price and stock status from this - Extract as DECIMAL NUMBER (convert comma to dot): 12,99 -> 12.99 - Ignore crossed-out/barré prices (old prices) - If multiple prices, take the current/main price (not the original) + +**CRITICAL - Read digits carefully:** +- PAY CLOSE ATTENTION to first digit: "1,99 €" is NOT "9,99 €" +- Double-check: Is it 1, 7, 8, or 9? These look similar +- Small prices (< 5€) are common: 0,99 €, 1,49 €, 1,99 €, 2,99 €, 3,99 €, 4,99 € +- VERIFY the price makes sense for the product type + - Examples of valid prices: + * "1,99 €" -> 1.99 (NOT 9.99) + * "0,99 €" -> 0.99 (NOT 9.99) * "89,99 €" -> 89.99 * "1 234,56 €" -> 1234.56 * "PRIX DÉTECTÉ: 89,99 €" -> 89.99 - If you find ANY price with € symbol, extract it with confidence >= 0.8 +- If digits are unclear or blurry, reduce confidence to 0.5-0.7 - If unclear: set null and confidence < 0.5 **STOCK:** diff --git a/app/services/ai_service.py b/app/services/ai_service.py index 60096ae..71da37a 100644 --- a/app/services/ai_service.py +++ b/app/services/ai_service.py @@ -343,14 +343,22 @@ class AIService: if len(cleaned_text) > MAX_TEXT_LENGTH: cleaned_text = cleaned_text[:MAX_TEXT_LENGTH] + "...(truncated)" logger.info(f"Added text context (original: {len(page_text)}, cleaned: {len(cleaned_text)})") - # Debug: Log first 500 chars of cleaned text to see what AI receives - logger.debug(f"Cleaned text preview: {cleaned_text[:500]!r}") + # Log first 500 chars of cleaned text to see what AI receives + logger.info(f"Cleaned text preview: {cleaned_text[:500]!r}") + + # Extract all potential prices from text for debugging + import re + price_patterns = re.findall(r'\d+[,\.]\d{2}\s*€', cleaned_text) + if price_patterns: + logger.info(f"Prices found in text: {price_patterns[:10]}") # First 10 prices + else: + logger.warning("No prices found in text with € symbol") else: logger.warning("No page_text provided - AI will only use screenshot") prompt = get_extraction_prompt(cleaned_text if cleaned_text else None) - # Debug: Log prompt preview - logger.debug(f"Prompt preview (first 300 chars): {prompt[:300]!r}") + # Log prompt preview + logger.info(f"Prompt preview (first 300 chars): {prompt[:300]!r}") # Call LLM response_text = await cls.call_llm(prompt, data_url, config)