rairo commited on
Commit
cb599e6
·
verified ·
1 Parent(s): 646ce38

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +32 -21
main.py CHANGED
@@ -1,9 +1,9 @@
1
  """
2
- main.py — Pricelyst Shopping Advisor (Jessica Edition 2026 - Upgrade v2.3)
3
 
4
- ✅ Fixed: Image Endpoint now auto-resolves prices (Simulated Intent).
5
- ✅ Fixed: Vision SDK Crash (Part.from_text removed).
6
- ✅ Fixed: "Clingy" Memory (Topic Reset Rule added).
7
  ✅ "Analyst Engine": Enhanced Basket Math, Category Context, ZESA Logic.
8
  ✅ "Visual Engine": Lists, Products, & Meal-to-Recipe recognition.
9
  ✅ Memory Logic: Short-Term Sliding Window (Last 6 messages).
@@ -457,15 +457,17 @@ def gemini_analyze_image(image_b64: str, caption: str = "") -> Dict[str, Any]:
457
 
458
  PROMPT = f"""
459
  Analyze this image. Context: {caption}
460
- 1. Is it a handwritten/printed SHOPPING LIST? -> Extract items.
461
- 2. Is it a SINGLE PRODUCT? -> Identify the product name.
462
- 3. Is it a MEAL/DISH? -> Identify the dish and list key ingredients to buy.
463
- 4. IRRELEVANT? -> Return type "IRRELEVANT".
 
 
464
 
465
  Return STRICT JSON:
466
  {{
467
  "type": "LIST" | "PRODUCT" | "MEAL" | "IRRELEVANT",
468
- "items": ["item1", "item2"],
469
  "description": "Short description of what is seen"
470
  }}
471
  """
@@ -512,7 +514,7 @@ def gemini_chat_response(transcript: str, intent: Dict, analyst_data: Dict, chat
512
  - **Casual**: Warm greeting. If they just said "Hi", reply "Makadii! How can I help you save today?". Don't summarize past chats.
513
  - **Advice**: If data exists, guide them. "I found XYZ at Store A."
514
  - **Trust**: If user asks "Is this expensive?", check 'category_stats'.
515
- - **ZESA**: Explain units clearly.
516
 
517
  TONE: Conversational, Zimbabwean English.
518
  """
@@ -561,7 +563,7 @@ def health():
561
  "ok": True,
562
  "offers_indexed": len(df),
563
  "api_source": PRICE_API_BASE,
564
- "persona": "Jessica v2.3"
565
  })
566
 
567
  @app.post("/chat")
@@ -646,34 +648,39 @@ def analyze_image():
646
  vision_result = gemini_analyze_image(image_b64, caption)
647
  img_type = vision_result.get("type", "IRRELEVANT")
648
  items = vision_result.get("items", [])
649
- description = vision_result.get("description", "item")
650
 
 
 
 
 
 
 
 
 
651
  response_text = ""
652
  analyst_data = {}
653
 
654
  # 2. Logic Branching
655
- if img_type == "IRRELEVANT":
656
- response_text = "I see the image, but I can't find any shopping items or meals in it. Try a receipt, a product, or a plate of food!"
 
 
657
 
658
  elif items:
659
  # Run the Analyst Engine
660
  analyst_data = calculate_basket_optimization(items)
661
 
662
  # 3. DYNAMIC SIMULATED INTENT
663
- # We vary the "user voice" so Jessica's reply matches the context.
664
-
665
  if img_type == "MEAL":
666
- # Context: "I want to cook this"
667
- simulated_user_msg = f"I want to cook {description}. I need these ingredients: {', '.join(items)}. How much will it cost to make this?"
668
- intent_sim = {"intent": "SHOPPING_BASKET"} # Triggers advice mode
669
 
670
  elif img_type == "LIST":
671
- # Context: "Quote this list"
672
  simulated_user_msg = f"Here is my shopping list: {', '.join(items)}. Which store is cheapest for the whole basket?"
673
  intent_sim = {"intent": "STORE_DECISION"}
674
 
675
  else: # PRODUCT
676
- # Context: "Price check"
677
  simulated_user_msg = f"I see {description}. Which store has the cheapest price for it right now?"
678
  intent_sim = {"intent": "STORE_DECISION"}
679
 
@@ -685,6 +692,10 @@ def analyze_image():
685
  chat_history="" # Fresh context
686
  )
687
 
 
 
 
 
688
  return jsonify({
689
  "ok": True,
690
  "image_type": img_type,
 
1
  """
2
+ main.py — Pricelyst Shopping Advisor (Jessica Edition 2026 - Upgrade v2.4)
3
 
4
+ ✅ Fixed: Vision Prompt now forces item extraction for Products/Meals.
5
+ ✅ Fixed: "Nice Dog" Logic. Irrelevant images get a Persona response, not an error.
6
+ ✅ Fixed: "Limbo State". Fallback logic ensures 'Pepsi' is searched even if items=[] initially.
7
  ✅ "Analyst Engine": Enhanced Basket Math, Category Context, ZESA Logic.
8
  ✅ "Visual Engine": Lists, Products, & Meal-to-Recipe recognition.
9
  ✅ Memory Logic: Short-Term Sliding Window (Last 6 messages).
 
457
 
458
  PROMPT = f"""
459
  Analyze this image. Context: {caption}
460
+ 1. SHOPPING LIST? -> Extract items.
461
+ 2. SINGLE PRODUCT? -> Extract the BRAND and PRODUCT NAME into 'items'. (e.g. "Pepsi 500ml")
462
+ 3. MEAL/DISH? -> Identify the dish and ingredients.
463
+ 4. IRRELEVANT (Pet, Person, Nature)? -> Return type "IRRELEVANT".
464
+
465
+ IMPORTANT: If type is 'PRODUCT', the 'items' list MUST contain the product name. Do not leave it empty.
466
 
467
  Return STRICT JSON:
468
  {{
469
  "type": "LIST" | "PRODUCT" | "MEAL" | "IRRELEVANT",
470
+ "items": ["item1"],
471
  "description": "Short description of what is seen"
472
  }}
473
  """
 
514
  - **Casual**: Warm greeting. If they just said "Hi", reply "Makadii! How can I help you save today?". Don't summarize past chats.
515
  - **Advice**: If data exists, guide them. "I found XYZ at Store A."
516
  - **Trust**: If user asks "Is this expensive?", check 'category_stats'.
517
+ - **Irrelevant Images**: If user sent a photo of a dog/nature, compliment it warmly, then gently mention you specialize in shopping.
518
 
519
  TONE: Conversational, Zimbabwean English.
520
  """
 
563
  "ok": True,
564
  "offers_indexed": len(df),
565
  "api_source": PRICE_API_BASE,
566
+ "persona": "Jessica v2.4"
567
  })
568
 
569
  @app.post("/chat")
 
648
  vision_result = gemini_analyze_image(image_b64, caption)
649
  img_type = vision_result.get("type", "IRRELEVANT")
650
  items = vision_result.get("items", [])
651
+ description = vision_result.get("description", "an image")
652
 
653
+ # Fallback: If type is PRODUCT/MEAL but items is empty, try to use description as search item
654
+ # This catches the "Pepsi bottle" case where items was []
655
+ if (img_type in ["PRODUCT", "MEAL"]) and not items and description:
656
+ # Simple heuristic: treat the description as the item for fuzzy search
657
+ # It won't be perfect, but it prevents the "silent failure"
658
+ items = [description]
659
+ logger.info(f"🔮 Fallback: Used description '{description}' as item.")
660
+
661
  response_text = ""
662
  analyst_data = {}
663
 
664
  # 2. Logic Branching
665
+ if img_type == "IRRELEVANT" and not items:
666
+ # Graceful Rejection / Compliment
667
+ prompt = f"User uploaded a photo of: {description}. If it is a pet/flower/view, compliment it warmly! Then effectively explain you are a shopping bot and can't price check that."
668
+ response_text = gemini_chat_response(prompt, {"intent": "CASUAL_CHAT"}, {}, "")
669
 
670
  elif items:
671
  # Run the Analyst Engine
672
  analyst_data = calculate_basket_optimization(items)
673
 
674
  # 3. DYNAMIC SIMULATED INTENT
 
 
675
  if img_type == "MEAL":
676
+ simulated_user_msg = f"I want to cook {description}. I need these ingredients: {', '.join(items)}. How much will it cost?"
677
+ intent_sim = {"intent": "SHOPPING_BASKET"}
 
678
 
679
  elif img_type == "LIST":
 
680
  simulated_user_msg = f"Here is my shopping list: {', '.join(items)}. Which store is cheapest for the whole basket?"
681
  intent_sim = {"intent": "STORE_DECISION"}
682
 
683
  else: # PRODUCT
 
684
  simulated_user_msg = f"I see {description}. Which store has the cheapest price for it right now?"
685
  intent_sim = {"intent": "STORE_DECISION"}
686
 
 
692
  chat_history="" # Fresh context
693
  )
694
 
695
+ else:
696
+ # Catch-all if something really weird happens (Product type but no description/items)
697
+ response_text = "I couldn't quite identify the product in that image. Could you type the name for me?"
698
+
699
  return jsonify({
700
  "ok": True,
701
  "image_type": img_type,