DreamStream-1 commited on
Commit
3ccc5ef
·
verified ·
1 Parent(s): 776c200

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -797
app.py CHANGED
@@ -1,7 +1,7 @@
1
  #!/usr/bin/env python3
2
  """
3
- Apex Biotical Veterinary WhatsApp Bot - Premium Edition
4
- The most effective and accurate veterinary chatbot in the market
5
  """
6
 
7
  import os
@@ -60,7 +60,7 @@ logger = logging.getLogger(__name__)
60
  load_dotenv()
61
 
62
  # Initialize FastAPI app
63
- app = FastAPI(title="Apex Biotical Veterinary Bot", version="2.0.0")
64
 
65
  # Ensure static and uploads directories exist before mounting
66
  os.makedirs('static', exist_ok=True)
@@ -280,7 +280,7 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
280
  model="whisper-1",
281
  file=audio_file,
282
  language="en", # Force English first
283
- prompt="This is a voice message for a veterinary products bot. Language: English or Urdu only. Common greetings: hi, hello, hey, salam, assalamualaikum. Numbers: one, two, three, 1, 2, 3, aik, do, teen. Menu options: search, browse, download, catalog, products, categories, contact, availability. Products: hydropex, heposel, bromacid, tribiotic, symodex, adek gold. Please transcribe clearly and accurately."
284
  )
285
 
286
  transcribed_text = transcript.text.strip()
@@ -295,7 +295,7 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
295
  model="whisper-1",
296
  file=audio_file,
297
  language="ur", # Force Urdu
298
- prompt="This is a voice message in Urdu for a veterinary products bot. Common Urdu greetings: سلام, ہیلو, ہائے, السلام علیکم, وعلیکم السلام. Numbers: ایک, دو, تین, چار, پانچ, 1, 2, 3, 4, 5. Menu options: تلاش, براؤز, ڈاؤن لوڈ, کیٹلاگ, پروڈکٹ, کیٹیگری, رابطہ, دستیابی. Products: ہائیڈروپیکس, ہیپوسیل, بروماسڈ, ٹرائیبیوٹک. Please transcribe clearly in Urdu or English."
299
  )
300
 
301
  transcribed_text = transcript.text.strip()
@@ -309,7 +309,7 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
309
  transcript = openai.Audio.transcribe(
310
  model="whisper-1",
311
  file=audio_file,
312
- prompt="This is a voice message for a veterinary products bot. Language: English or Urdu only. Common words: hi, hello, salam, one, two, three, aik, do, teen, search, browse, download, catalog, products, categories, contact, availability, hydropex, heposel, bromacid, tribiotic, symodex, adek gold. Please transcribe any speech you can hear, even if unclear. Numbers and menu selections are important."
313
  )
314
 
315
  transcribed_text = transcript.text.strip()
@@ -1044,6 +1044,9 @@ async def get_catalog():
1044
  @app.get("/", response_class=HTMLResponse)
1045
  async def root():
1046
  return """
 
 
 
1047
  <h2>Apex Biotical Veterinary WhatsApp Bot</h2>
1048
  <p>The bot is running! Use the API endpoints for WhatsApp integration.</p>
1049
  <ul>
@@ -1539,808 +1542,39 @@ async def process_incoming_message(from_number: str, msg: dict):
1539
  # This ensures users can say product names like "hydropex", "respira aid plus", etc. from any menu
1540
  logger.info(f"[Process] Checking for product name in message: '{message_body}' from state: {current_state}")
1541
  products = get_veterinary_product_matches(message_body)
1542
-
1543
- if products:
1544
- logger.info(f"[Process] Product name detected: '{message_body}' -> Found {len(products)} products")
1545
-
1546
- # If single product found, show it directly
1547
- if len(products) == 1:
1548
- selected_product = products[0]
1549
- product_name = selected_product.get('Product Name', 'Unknown')
1550
- logger.info(f"[Process] Single product found: {product_name}")
1551
-
1552
- # Set current product and show details
1553
- context_manager.update_context(
1554
- from_number,
1555
- current_product=selected_product,
1556
- current_state='product_inquiry',
1557
- current_menu='product_inquiry',
1558
- current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
1559
- )
1560
-
1561
- # Generate and send product response
1562
- response = generate_veterinary_product_response(selected_product, user_context)
1563
- send_whatsjet_message(from_number, response)
1564
- return
1565
-
1566
- # If multiple products found, show list for selection
1567
- elif len(products) > 1:
1568
- logger.info(f"[Process] Multiple products found: {len(products)} products")
1569
-
1570
- # Use OpenAI to generate a professional summary and list all products
1571
- if OPENAI_API_KEY:
1572
- try:
1573
- # Create a comprehensive prompt for multiple products
1574
- products_info = []
1575
- for i, product in enumerate(products, 1):
1576
- product_name = product.get('Product Name', 'N/A')
1577
- category = product.get('Category', 'N/A')
1578
- target_species = product.get('Target Species', 'N/A')
1579
- products_info.append(f"{i}. {product_name} - {category} ({target_species})")
1580
-
1581
- products_text = "\n".join(products_info)
1582
-
1583
- prompt = f"""
1584
- You are a professional veterinary product assistant for Apex Biotical. The user asked about "{message_body}" and we found {len(products)} relevant products.
1585
-
1586
- Available Products:
1587
- {products_text}
1588
-
1589
- Please provide:
1590
- 1. A professional, welcoming response acknowledging their query
1591
- 2. A brief summary of what these products are for (if it's a category like "poultry products", explain the category)
1592
- 3. List all products with their numbers and brief descriptions
1593
- 4. Clear instructions on how to proceed
1594
-
1595
- Format your response professionally with emojis and clear structure. Keep it concise but informative.
1596
- """
1597
-
1598
- response = openai.ChatCompletion.create(
1599
- model="gpt-4o",
1600
- messages=[{"role": "user", "content": prompt}],
1601
- temperature=0.7,
1602
- max_tokens=400
1603
- )
1604
-
1605
- ai_response = response.choices[0].message.content.strip()
1606
-
1607
- # Add instructions for selection
1608
- selection_instructions = (
1609
- f"\n\n💬 *To view detailed information about any product, reply with its number (1-{len(products)})*\n"
1610
- "💬 *Type 'main' to return to the main menu*"
1611
- )
1612
-
1613
- full_response = ai_response + selection_instructions
1614
-
1615
- # Translate response if needed
1616
- if reply_language == 'ur':
1617
- try:
1618
- translated_response = GoogleTranslator(source='auto', target='ur').translate(full_response)
1619
- send_whatsjet_message(from_number, translated_response)
1620
- except Exception as e:
1621
- logger.error(f"[AI] Translation error: {e}")
1622
- send_whatsjet_message(from_number, full_response)
1623
- else:
1624
- send_whatsjet_message(from_number, full_response)
1625
-
1626
- # Store the product list in context for selection handling
1627
- context_manager.update_context(
1628
- from_number,
1629
- current_state='intelligent_products_menu',
1630
- current_menu='intelligent_products_menu',
1631
- current_menu_options=[f"Product {i+1}" for i in range(len(products))],
1632
- available_products=products,
1633
- last_query=message_body
1634
- )
1635
-
1636
- # Add to conversation history
1637
- context_manager.add_to_history(from_number, message_body, full_response)
1638
- return
1639
-
1640
- except Exception as e:
1641
- logger.error(f"[AI] Error generating product summary: {e}")
1642
- # Fall back to simple listing if AI fails
1643
- pass
1644
-
1645
- # Fallback: Simple listing without AI
1646
- message = f"🔍 *Found {len(products)} products matching '{message_body}':*\n\n"
1647
-
1648
- for i, product in enumerate(products, 1):
1649
- product_name = product.get('Product Name', 'N/A')
1650
- category = product.get('Category', 'N/A')
1651
- target_species = product.get('Target Species', 'N/A')
1652
- message += f"{format_number_with_emoji(i)} {product_name}\n"
1653
- message += f" 📦 {category} ({target_species})\n\n"
1654
-
1655
- message += (
1656
- f"💬 *To view detailed information about any product, reply with its number (1-{len(products)})*\n"
1657
- "💬 *Type 'main' to return to the main menu*"
1658
- )
1659
-
1660
- # Translate response if needed
1661
- if reply_language == 'ur':
1662
- try:
1663
- translated_message = GoogleTranslator(source='auto', target='ur').translate(message)
1664
- send_whatsjet_message(from_number, translated_message)
1665
- except Exception as e:
1666
- logger.error(f"[AI] Translation error: {e}")
1667
- send_whatsjet_message(from_number, message)
1668
- else:
1669
- send_whatsjet_message(from_number, message)
1670
-
1671
- # Store the product list in context for selection handling
1672
- context_manager.update_context(
1673
- from_number,
1674
- current_state='intelligent_products_menu',
1675
- current_menu='intelligent_products_menu',
1676
- current_menu_options=[f"Product {i+1}" for i in range(len(products))],
1677
- available_products=products,
1678
- last_query=message_body
1679
- )
1680
-
1681
- # Add to conversation history
1682
- context_manager.add_to_history(from_number, message_body, message)
1683
- return
1684
-
1685
- # If no product found, continue with normal menu processing
1686
- logger.info(f"[Process] No product name detected, continuing with menu processing")
1687
-
1688
- # Handle state-specific menu selections with intelligent voice command processing
1689
- # Handle product follow-up menu selections (must be first)
1690
- if current_state == 'product_inquiry':
1691
- # Use intelligent voice command processor for better understanding
1692
- mapped_selection = process_intelligent_voice_command(message_body, current_state, user_context)
1693
- logger.info(f"[Process] Product inquiry selection mapped: '{message_body}' -> '{mapped_selection}'")
1694
-
1695
- # Check for main navigation first
1696
- if mapped_selection == 'main':
1697
- logger.info(f"[Process] Main navigation from product_inquiry: '{message_body}' -> 'main'")
1698
- welcome_msg = generate_veterinary_welcome_message()
1699
- send_whatsjet_message(from_number, welcome_msg)
1700
- context_manager.update_context(
1701
- from_number,
1702
- current_state='main_menu',
1703
- current_menu='main_menu',
1704
- current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values())
1705
- )
1706
- return
1707
-
1708
- # Validate menu selection using the mapped selection
1709
- if is_valid_menu_selection(mapped_selection, current_state, user_context):
1710
- await handle_veterinary_product_followup(mapped_selection, from_number)
1711
- return
1712
- else:
1713
- # If not a valid menu selection, treat as contact inquiry response
1714
- logger.info(f"[Process] Invalid menu selection in product_inquiry, treating as contact inquiry: '{message_body}'")
1715
- await handle_contact_request_response(from_number, message_body)
1716
- return
1717
-
1718
- # Handle contact request responses
1719
- if current_state == 'contact_request':
1720
- await handle_contact_request_response(from_number, message_body)
1721
- return
1722
-
1723
- # Handle availability inquiry responses
1724
- if current_state == 'availability_request':
1725
- await handle_availability_request_response(from_number, message_body)
1726
- return
1727
-
1728
- # Handle category product selections
1729
- if current_state == 'category_products_menu':
1730
- # Use intelligent voice command processor
1731
- mapped_selection = process_intelligent_voice_command(message_body, current_state, user_context)
1732
- logger.info(f"[Process] Category product selection mapped: '{message_body}' -> '{mapped_selection}'")
1733
-
1734
- # Check for main navigation first
1735
- if mapped_selection == 'main':
1736
- logger.info(f"[Process] Main navigation from category_products_menu: '{message_body}' -> 'main'")
1737
- welcome_msg = generate_veterinary_welcome_message()
1738
- send_whatsjet_message(from_number, welcome_msg)
1739
- context_manager.update_context(
1740
- from_number,
1741
- current_state='main_menu',
1742
- current_menu='main_menu',
1743
- current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values())
1744
- )
1745
- return
1746
-
1747
- # Validate menu selection using the mapped selection
1748
- if is_valid_menu_selection(mapped_selection, current_state, user_context):
1749
- await handle_category_product_selection(from_number, mapped_selection, user_context)
1750
- return
1751
- else:
1752
- # Invalid menu selection - send specific error message
1753
- error_msg = get_menu_validation_message(current_state, user_context)
1754
- send_whatsjet_message(from_number, error_msg)
1755
- return
1756
-
1757
- # Handle all products menu selections FIRST (before main menu)
1758
- if current_state == 'all_products_menu':
1759
- logger.info(f"[Process] Handling all_products_menu selection: '{message_body}'")
1760
- logger.info(f"[Process] User context state: {user_context.get('current_state')}")
1761
- logger.info(f"[Process] Message body type: {type(message_body)}, value: '{message_body}'")
1762
-
1763
- # Use intelligent voice command processor
1764
- mapped_selection = process_intelligent_voice_command(message_body, current_state, user_context)
1765
- logger.info(f"[Process] Mapped selection: '{message_body}' -> '{mapped_selection}'")
1766
-
1767
- # Check for main navigation first
1768
- if mapped_selection == 'main':
1769
- logger.info(f"[Process] Main navigation from all_products_menu: '{message_body}' -> 'main'")
1770
- welcome_msg = generate_veterinary_welcome_message()
1771
- send_whatsjet_message(from_number, welcome_msg)
1772
- context_manager.update_context(
1773
- from_number,
1774
- current_state='main_menu',
1775
- current_menu='main_menu',
1776
- current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values())
1777
- )
1778
- return
1779
-
1780
- # Validate menu selection using the mapped selection
1781
- if is_valid_menu_selection(mapped_selection, current_state, user_context):
1782
- logger.info(f"[Process] Valid selection: {mapped_selection}, proceeding to handle_all_products_selection")
1783
- await handle_all_products_selection(from_number, mapped_selection, user_context)
1784
- logger.info(f"[Process] Completed all_products_menu handling")
1785
- return
1786
- else:
1787
- # Invalid menu selection - send specific error message
1788
- error_msg = get_menu_validation_message(current_state, user_context)
1789
- send_whatsjet_message(from_number, error_msg)
1790
- return
1791
-
1792
- # Handle category selection menu
1793
- if current_state == 'category_selection_menu':
1794
- # Use intelligent voice command processor
1795
- mapped_selection = process_intelligent_voice_command(message_body, current_state, user_context)
1796
- logger.info(f"[Process] Category selection mapped: '{message_body}' -> '{mapped_selection}'")
1797
-
1798
- # Check for main navigation first
1799
- if mapped_selection == 'main':
1800
- logger.info(f"[Process] Main navigation from category_selection_menu: '{message_body}' -> 'main'")
1801
- welcome_msg = generate_veterinary_welcome_message()
1802
- send_whatsjet_message(from_number, welcome_msg)
1803
- context_manager.update_context(
1804
- from_number,
1805
- current_state='main_menu',
1806
- current_menu='main_menu',
1807
- current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values())
1808
- )
1809
- return
1810
-
1811
- # Validate menu selection using the mapped selection
1812
- if is_valid_menu_selection(mapped_selection, current_state, user_context):
1813
- await handle_category_selection(mapped_selection, from_number)
1814
- return
1815
- else:
1816
- # Invalid menu selection - send specific error message
1817
- error_msg = get_menu_validation_message(current_state, user_context)
1818
- send_whatsjet_message(from_number, error_msg)
1819
- return
1820
-
1821
- # Handle general menu selections (ONLY for main_menu state) with intelligent processing
1822
- if current_state == 'main_menu':
1823
- # Use intelligent voice command processor for better understanding
1824
- mapped_selection = process_intelligent_voice_command(message_body, current_state, user_context)
1825
- logger.info(f"[Process] Main menu selection mapped: '{message_body}' -> '{mapped_selection}'")
1826
-
1827
- if mapped_selection in ['1', '2', '3', '4']:
1828
- await handle_veterinary_menu_selection_complete(mapped_selection, from_number)
1829
- return
1830
- else:
1831
- # Invalid menu selection - send specific error message
1832
- error_msg = get_menu_validation_message(current_state, user_context)
1833
- send_whatsjet_message(from_number, error_msg)
1834
- return
1835
-
1836
- # Handle AI Chat Mode - completely separate from menu system
1837
- if current_state == 'ai_chat_mode':
1838
- logger.info(f"[AI Chat] Processing query in AI chat mode: '{message_body}' for {from_number}")
1839
- await handle_ai_chat_mode(from_number, message_body, reply_language)
1840
- return
1841
-
1842
- # If we reach here, we're not in a menu state - allow AI processing for general inquiries
1843
- # Expanded keyword list for product/general queries (English + Urdu)
1844
- product_keywords = [
1845
- 'product', 'information', 'details', 'about', 'poultry', 'veterinary', 'medicine', 'treatment',
1846
- 'products', 'catalog', 'category', 'categories', 'list', 'all',
1847
- 'پروڈکٹ', 'معلومات', 'تفصیل', 'ادویات', 'علاج', 'جانور', 'دوائی', 'کیٹلاگ', 'فہرست', 'تمام', 'کیٹیگری', 'کیٹیگریز'
1848
- ]
1849
- # Lowercase and normalize message for keyword matching
1850
- msg_lower = message_body.lower().strip()
1851
- if any(keyword in msg_lower for keyword in product_keywords):
1852
- logger.info(f"[Process] Detected product/general inquiry (OpenAI) in message: '{message_body}'")
1853
- # User-facing message for voice/general queries
1854
- if reply_language == 'ur':
1855
- send_whatsjet_message(from_number, "🤖 آپ کے request کو ہمارے Veterinary AI assistant کے ساتھ process کر رہا ہوں...")
1856
- else:
1857
- send_whatsjet_message(from_number, "🤖 Processing your request with our Veterinary AI assistant...")
1858
- # Get OpenAI response with reply_language parameter
1859
- await handle_intelligent_product_inquiry(from_number, message_body, user_context, reply_language)
1860
- return
1861
- else:
1862
- # General free-form query (OpenAI)
1863
- logger.info(f"[Process] Detected general free-form inquiry (OpenAI) in message: '{message_body}'")
1864
- if reply_language == 'ur':
1865
- send_whatsjet_message(from_number, "🤖 آپ کے request کو ہمارے Veterinary AI assistant کے ساتھ process کر رہا ہوں...")
1866
- else:
1867
- send_whatsjet_message(from_number, "🤖 Processing your request with our Veterinary AI assistant...")
1868
- await handle_general_query_with_ai(from_number, message_body, user_context, reply_language)
1869
- return
1870
-
1871
- except Exception as e:
1872
- logger.error(f"[Process] Error processing message: {e}")
1873
- send_whatsjet_message(from_number,
1874
- "❌ Sorry, I encountered an error. Please try again or type 'main' to return to the main menu.")
1875
 
1876
- async def handle_voice_message_complete(from_number: str, msg: dict):
1877
- """Complete voice message processing with OpenAI transcription - treats voice exactly like text"""
1878
- try:
1879
- logger.info(f"[Voice] Processing voice message from {from_number}")
1880
- logger.info(f"[Voice] Message structure: {msg}")
1881
-
1882
- # Check if OpenAI is available
1883
- if not OPENAI_API_KEY:
1884
- send_whatsjet_message(from_number,
1885
- "🎤 Voice messages require OpenAI API. Please send a text message or type 'main' to see the menu.")
1886
- return
1887
-
1888
- # Extract media URL from different possible locations
1889
- media_url = None
1890
- logger.info(f"[Voice] Checking media URL locations...")
1891
-
1892
- if msg.get('media', {}).get('link'):
1893
- media_url = msg.get('media', {}).get('link')
1894
- logger.info(f"[Voice] Found media URL in media.link: {media_url}")
1895
- elif msg.get('media', {}).get('url'):
1896
- media_url = msg.get('media', {}).get('url')
1897
- logger.info(f"[Voice] Found media URL in media.url: {media_url}")
1898
- elif msg.get('url'):
1899
- media_url = msg.get('url')
1900
- logger.info(f"[Voice] Found media URL in url: {media_url}")
1901
- elif msg.get('audio', {}).get('url'):
1902
- media_url = msg.get('audio', {}).get('url')
1903
- logger.info(f"[Voice] Found media URL in audio.url: {media_url}")
1904
- else:
1905
- logger.error(f"[Voice] No media URL found in message structure")
1906
- logger.error(f"[Voice] Available fields: {list(msg.keys())}")
1907
- if 'media' in msg:
1908
- logger.error(f"[Voice] Media fields: {list(msg['media'].keys())}")
1909
-
1910
- logger.info(f"[Voice] Final extracted media URL: {media_url}")
1911
-
1912
- if not media_url:
1913
- send_whatsjet_message(from_number, "❌ Could not process voice message. Please try again.")
1914
- return
1915
-
1916
- # Generate unique filename
1917
- filename = f"voice_{from_number}_{int(time.time())}.ogg"
1918
-
1919
- # Download voice file
1920
- file_path = await download_voice_file(media_url, filename)
1921
- if not file_path:
1922
- send_whatsjet_message(from_number, "❌ Failed to download voice message. Please try again.")
1923
- return
1924
-
1925
- # Transcribe with OpenAI
1926
- transcribed_text = await transcribe_voice_with_openai(file_path)
1927
-
1928
- # Clean up voice file immediately
1929
- try:
1930
- os.remove(file_path)
1931
- except:
1932
- pass
1933
-
1934
- # Handle empty or failed transcription
1935
- if not transcribed_text or transcribed_text.strip() == "":
1936
- logger.warning(f"[Voice] Empty transcription for {from_number}")
1937
- send_whatsjet_message(from_number,
1938
- "🎤 *Voice Message Issue*\n\n"
1939
- "I couldn't hear anything in your voice message. This can happen due to:\n"
1940
- "• Very short voice note\n"
1941
- "• Background noise\n"
1942
- "• Microphone too far away\n"
1943
- "• Audio quality issues\n\n"
1944
- "💡 *Tips for better voice notes:*\n"
1945
- "• Speak clearly and slowly\n"
1946
- "• Keep phone close to mouth\n"
1947
- "• Record in quiet environment\n"
1948
- "• Make voice note at least 2-3 seconds\n\n"
1949
- "💬 *You can also:*\n"
1950
- "• Send a text message\n"
1951
- "• Type 'main' to see menu options\n"
1952
- "• Try voice note again")
1953
- return
1954
-
1955
- # Process transcribed text with full intelligence
1956
- logger.info(f"[Voice] Transcribed: {transcribed_text}")
1957
-
1958
- # Apply transcription error corrections
1959
- corrected_text = process_voice_input(transcribed_text)
1960
- if corrected_text != transcribed_text:
1961
- logger.info(f"[Voice] Applied corrections: '{transcribed_text}' -> '{corrected_text}'")
1962
- transcribed_text = corrected_text
1963
-
1964
- # Detect language of transcribed text
1965
- detected_lang = 'en' # Default to English
1966
- try:
1967
- detected_lang = detect(transcribed_text)
1968
- logger.info(f"[Voice] Detected language: {detected_lang}")
1969
-
1970
- # Map language codes to supported languages
1971
- lang_mapping = {
1972
- 'ur': 'ur', # Urdu
1973
- 'ar': 'ur', # Arabic (treat as Urdu for Islamic greetings)
1974
- 'en': 'en', # English
1975
- 'hi': 'ur', # Hindi (treat as Urdu)
1976
- 'bn': 'ur', # Bengali (treat as Urdu)
1977
- 'pa': 'ur', # Punjabi (treat as Urdu)
1978
- 'id': 'ur', # Indonesian (often misdetected for Urdu/Arabic)
1979
- 'ms': 'ur', # Malay (often misdetected for Urdu/Arabic)
1980
- 'tr': 'ur', # Turkish (often misdetected for Urdu/Arabic)
1981
- }
1982
-
1983
- # Check if text contains Urdu/Arabic characters or Islamic greetings
1984
- urdu_arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
1985
- islamic_greetings = ['assalamu', 'assalam', 'salam', 'salaam', 'adaab', 'namaste', 'khuda', 'allah']
1986
-
1987
- has_urdu_chars = bool(urdu_arabic_pattern.search(transcribed_text))
1988
- has_islamic_greeting = any(greeting in transcribed_text.lower() for greeting in islamic_greetings)
1989
-
1990
- if has_urdu_chars or has_islamic_greeting:
1991
- detected_lang = 'ur'
1992
- logger.info(f"[Voice] Overriding language detection to Urdu due to Arabic/Urdu characters or Islamic greeting")
1993
-
1994
- reply_language = lang_mapping.get(detected_lang, 'en')
1995
- logger.info(f"[Voice] Language '{detected_lang}' mapped to: {reply_language}")
1996
-
1997
- except Exception as e:
1998
- logger.warning(f"[Voice] Language detection failed: {e}")
1999
- reply_language = 'en'
2000
-
2001
- if reply_language not in ['en', 'ur']:
2002
- logger.info(f"[Voice] Language '{reply_language}' not supported, defaulting to English")
2003
- reply_language = 'en'
2004
-
2005
- # For Urdu voice notes, translate to English for processing
2006
- processing_text = transcribed_text
2007
- if reply_language == 'ur' and detected_lang == 'ur':
2008
- try:
2009
- logger.info(f"[Voice] Translating Urdu voice note to English for processing")
2010
- translated_text = GoogleTranslator(source='ur', target='en').translate(transcribed_text)
2011
- processing_text = translated_text
2012
- logger.info(f"[Voice] Translated to English: {translated_text}")
2013
- except Exception as e:
2014
- logger.error(f"[Voice] Translation failed: {e}")
2015
- # If translation fails, use original text
2016
- processing_text = transcribed_text
2017
-
2018
- # Determine reply language - always respond in English or Urdu
2019
- if detected_lang == 'ur':
2020
- reply_language = 'ur' # Urdu voice notes get Urdu replies
2021
- else:
2022
- reply_language = 'en' # All other languages get English replies
2023
-
2024
- logger.info(f"[Voice] Processing text: {processing_text}")
2025
- logger.info(f"[Voice] Reply language set to: {reply_language}")
2026
-
2027
- # Check if this is a greeting in voice note (check both original and translated)
2028
- if is_greeting(transcribed_text) or is_greeting(processing_text):
2029
- logger.info(f"[Voice] Greeting detected in voice note: {transcribed_text}")
2030
-
2031
- # Check if user is currently in AI chat mode - if so, don't trigger menu mode
2032
- user_context = context_manager.get_context(from_number)
2033
- current_state = user_context.get('current_state', 'main_menu')
2034
-
2035
- if current_state == 'ai_chat_mode':
2036
- logger.info(f"[Voice] User is in AI chat mode, treating greeting as AI query instead of menu trigger")
2037
- # Treat greeting as a general query in AI chat mode
2038
- await handle_general_query_with_ai(from_number, processing_text, user_context, reply_language)
2039
- return
2040
- else:
2041
- # Only trigger menu mode if not in AI chat mode
2042
- welcome_msg = generate_veterinary_welcome_message()
2043
- send_whatsjet_message(from_number, welcome_msg)
2044
- context_manager.update_context(from_number, current_state='main_menu', current_menu='main_menu', current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values()))
2045
- return
2046
-
2047
- # Process the translated text using the same strict state-based logic as text messages
2048
- # This ensures voice messages follow the same menu and state rules as text messages
2049
- await process_incoming_message(from_number, {
2050
- 'body': processing_text, # Use translated text for processing
2051
- 'type': 'text',
2052
- 'reply_language': reply_language,
2053
- 'original_transcription': transcribed_text # Keep original for context
2054
- })
2055
-
2056
- except Exception as e:
2057
- logger.error(f"[Voice] Error processing voice message: {e}")
2058
- logger.error(f"[Voice] Full error details: {str(e)}")
2059
- import traceback
2060
- logger.error(f"[Voice] Traceback: {traceback.format_exc()}")
2061
- send_whatsjet_message(from_number,
2062
- "❌ Error processing voice message. Please try a text message.")
2063
-
2064
- async def handle_veterinary_menu_selection_complete(selection: str, from_number: str):
2065
- """Complete menu selection handling with all possible states and menu context"""
2066
- try:
2067
- user_context = context_manager.get_context(from_number)
2068
- current_state = user_context.get('current_state', 'main_menu')
2069
- current_menu = user_context.get('current_menu', current_state)
2070
- current_menu_options = user_context.get('current_menu_options', [])
2071
- logger.info(f"[Menu] Handling selection '{selection}' in state '{current_state}' (menu: {current_menu}) for {from_number}")
2072
-
2073
- # Validate selection
2074
- is_valid, error_msg = validate_menu_selection(selection, current_state, user_context)
2075
- if not is_valid:
2076
- send_whatsjet_message(from_number, error_msg)
2077
- return
2078
-
2079
- # Main menu - check current_state, not current_menu
2080
- if current_state == 'main_menu':
2081
- logger.info(f"[Menu] Processing main_menu selection: '{selection}' for {from_number}")
2082
- if selection == '1':
2083
- await display_all_products(from_number)
2084
- elif selection == '2':
2085
- categories = get_all_categories()
2086
- if not categories:
2087
- send_whatsjet_message(from_number, "❌ No categories available at the moment.")
2088
- return
2089
- category_message = "📁 *Browse Categories*\n\n"
2090
- for i, category in enumerate(categories, 1):
2091
- category_message += f"{format_number_with_emoji(i)} {category}\n"
2092
- category_message += "\nSelect a category number or type 'main' to return to main menu."
2093
- send_whatsjet_message(from_number, category_message)
2094
- context_manager.update_context(
2095
- from_number,
2096
- current_state='category_selection_menu',
2097
- current_menu='category_selection_menu',
2098
- current_menu_options=categories,
2099
- available_categories=categories
2100
- )
2101
- elif selection == '3':
2102
- await send_catalog_pdf(from_number)
2103
- context_manager.update_context(from_number, current_state='main_menu', current_menu='main_menu', current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values()))
2104
- elif selection == '4':
2105
- # Enter AI Chat Mode
2106
- ai_welcome_msg = (
2107
- "🤖 *Veterinary AI Assistant Activated*\n\n"
2108
- "I'm your intelligent veterinary assistant. I can help you with:\n"
2109
- "• Product information and recommendations\n"
2110
- "• Veterinary advice and guidance\n"
2111
- "• Treatment suggestions\n"
2112
- "• General veterinary questions\n\n"
2113
- "💬 *Ask me anything related to veterinary care!*\n"
2114
- "🎤 *Voice messages are supported*\n\n"
2115
- "Type 'main' to return to main menu."
2116
- )
2117
- send_whatsjet_message(from_number, ai_welcome_msg)
2118
- context_manager.update_context(
2119
- from_number,
2120
- current_state='ai_chat_mode',
2121
- current_menu='ai_chat_mode',
2122
- current_menu_options=['main']
2123
- )
2124
- else:
2125
- send_whatsjet_message(from_number, "❌ Invalid selection. Please choose 1, 2, 3, or 4.")
2126
-
2127
- # Product inquiry menu
2128
- elif current_menu == 'product_inquiry':
2129
- await handle_veterinary_product_followup(selection, from_number)
2130
-
2131
- # Intelligent products menu (for multiple product results)
2132
- elif current_menu == 'intelligent_products_menu':
2133
- available_products = user_context.get('available_products', [])
2134
- if selection.isdigit() and 1 <= int(selection) <= len(available_products):
2135
- selected_product = available_products[int(selection) - 1]
2136
- product_name = selected_product.get('Product Name', 'Unknown')
2137
- context_manager.update_context(from_number, current_product=selected_product, current_state='product_inquiry', current_menu='product_inquiry', current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values()))
2138
- response = generate_veterinary_product_response(selected_product, user_context)
2139
- send_whatsjet_message(from_number, response)
2140
- else:
2141
- send_whatsjet_message(from_number, f"❌ Invalid selection. Please choose a number between 1 and {len(available_products)}.")
2142
-
2143
- # Category selection menu
2144
- elif current_menu == 'category_selection_menu':
2145
- await handle_category_selection(selection, from_number)
2146
-
2147
- # Category products menu
2148
- elif current_menu == 'category_products_menu':
2149
- await handle_category_product_selection(from_number, selection, user_context)
2150
-
2151
- # All products menu
2152
- elif current_menu == 'all_products_menu':
2153
- await handle_all_products_selection(from_number, selection, user_context)
2154
-
2155
- else:
2156
- welcome_msg = generate_veterinary_welcome_message()
2157
- send_whatsjet_message(from_number, welcome_msg)
2158
- context_manager.update_context(from_number, current_state='main_menu', current_menu='main_menu', current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values()))
2159
-
2160
- except Exception as e:
2161
- logger.error(f"[Menu] Error handling menu selection: {e}")
2162
- welcome_msg = generate_veterinary_welcome_message()
2163
- send_whatsjet_message(from_number, welcome_msg)
2164
- context_manager.update_context(from_number, current_state='main_menu', current_menu='main_menu', current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values()))
2165
-
2166
- async def handle_category_product_selection(from_number: str, selection: str, user_context: dict):
2167
- """Handle product selection from category products menu"""
2168
- try:
2169
- available_products = user_context.get('available_products', [])
2170
- if selection.isdigit() and 1 <= int(selection) <= len(available_products):
2171
- selected_product = available_products[int(selection) - 1]
2172
- product_name = selected_product.get('Product Name', 'Unknown')
2173
- # Set current product and show details
2174
  context_manager.update_context(
2175
  from_number,
2176
- current_product=selected_product,
2177
  current_state='product_inquiry',
2178
  current_menu='product_inquiry',
2179
  current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
2180
  )
2181
- # Generate product response
2182
- response = generate_veterinary_product_response(selected_product, user_context)
2183
  send_whatsjet_message(from_number, response)
2184
- else:
2185
- send_whatsjet_message(from_number, "❌ Invalid selection. Please choose a valid product number.")
2186
- except Exception as e:
2187
- logger.error(f"[Category] Error handling product selection: {e}")
2188
- send_helpful_guidance(from_number, 'category_products_menu')
2189
-
2190
- async def handle_all_products_selection(from_number: str, selection: str, user_context: dict):
2191
- """Handle product selection from all products menu"""
2192
- try:
2193
- if products_df is None or products_df.empty:
2194
- send_whatsjet_message(from_number, "❌ No products available.")
2195
  return
2196
- products = products_df.to_dict('records')
2197
- if selection.isdigit() and 1 <= int(selection) <= len(products):
2198
- selected_index = int(selection) - 1
2199
- selected_product = products[selected_index]
2200
- product_name = selected_product.get('Product Name', 'Unknown')
2201
- logger.info(f"[All Products] Selected product: {product_name} (index {selected_index})")
2202
- # Set current product and show details
2203
- context_manager.update_context(
2204
- from_number,
2205
- current_product=selected_product,
2206
- current_state='product_inquiry',
2207
- current_menu='product_inquiry',
2208
- current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
2209
- )
2210
- response = generate_veterinary_product_response(selected_product, user_context)
2211
- send_whatsjet_message(from_number, response)
2212
- else:
2213
- send_whatsjet_message(from_number, "❌ Invalid selection. Please choose a valid product number.")
2214
- except Exception as e:
2215
- logger.error(f"[All Products] Error handling product selection: {e}")
2216
- send_helpful_guidance(from_number, 'all_products_menu')
2217
 
2218
- async def handle_intelligent_product_inquiry(from_number: str, query: str, user_context: dict, reply_language: str = 'en'):
2219
- """Handle product inquiry with OpenAI intelligence"""
2220
- try:
2221
- # First try direct product search
2222
- products = get_veterinary_product_matches(query)
2223
-
2224
  if products:
2225
- # Check if this is a broad/category query (multiple products found)
2226
- if len(products) > 1:
2227
- # Use OpenAI to generate a professional summary and list all products
2228
- if OPENAI_API_KEY:
2229
- try:
2230
- # Create a comprehensive prompt for multiple products
2231
- products_info = []
2232
- for i, product in enumerate(products, 1):
2233
- product_name = product.get('Product Name', 'N/A')
2234
- category = product.get('Category', 'N/A')
2235
- target_species = product.get('Target Species', 'N/A')
2236
- products_info.append(f"{i}. {product_name} - {category} ({target_species})")
2237
-
2238
- products_text = "\n".join(products_info)
2239
-
2240
- prompt = f"""
2241
- You are a professional veterinary product assistant for Apex Biotical. The user asked about "{query}" and we found {len(products)} relevant products.
2242
-
2243
- Available Products:
2244
- {products_text}
2245
-
2246
- Please provide:
2247
- 1. A professional, welcoming response acknowledging their query
2248
- 2. A brief summary of what these products are for (if it's a category like "poultry products", explain the category)
2249
- 3. List all products with their numbers and brief descriptions
2250
- 4. Clear instructions on how to proceed
2251
-
2252
- Format your response professionally with emojis and clear structure. Keep it concise but informative.
2253
- """
2254
-
2255
- response = openai.ChatCompletion.create(
2256
- model="gpt-4o",
2257
- messages=[{"role": "user", "content": prompt}],
2258
- temperature=0.7,
2259
- max_tokens=400
2260
- )
2261
-
2262
- ai_response = response.choices[0].message.content.strip()
2263
-
2264
- # Add instructions for selection
2265
- selection_instructions = (
2266
- f"\n\n💬 *To view detailed information about any product, reply with its number (1-{len(products)})*\n"
2267
- "💬 *Type 'main' to return to the main menu*"
2268
- )
2269
-
2270
- full_response = ai_response + selection_instructions
2271
-
2272
- # Translate response if needed
2273
- if reply_language == 'ur':
2274
- try:
2275
- translated_response = GoogleTranslator(source='auto', target='ur').translate(full_response)
2276
- send_whatsjet_message(from_number, translated_response)
2277
- except Exception as e:
2278
- logger.error(f"[AI] Translation error: {e}")
2279
- send_whatsjet_message(from_number, full_response)
2280
- else:
2281
- send_whatsjet_message(from_number, full_response)
2282
-
2283
- # Store the product list in context for selection handling
2284
- context_manager.update_context(
2285
- from_number,
2286
- current_state='intelligent_products_menu',
2287
- current_menu='intelligent_products_menu',
2288
- current_menu_options=[f"Product {i+1}" for i in range(len(products))],
2289
- available_products=products,
2290
- last_query=query
2291
- )
2292
-
2293
- # Add to conversation history
2294
- context_manager.add_to_history(from_number, query, full_response)
2295
- return
2296
-
2297
- except Exception as e:
2298
- logger.error(f"[AI] Error generating product summary: {e}")
2299
- # Fall back to simple listing if AI fails
2300
- pass
2301
-
2302
- # Fallback: Simple listing without AI
2303
- message = f"🔍 *Found {len(products)} products matching '{query}':*\n\n"
2304
-
2305
- for i, product in enumerate(products, 1):
2306
- product_name = product.get('Product Name', 'N/A')
2307
- category = product.get('Category', 'N/A')
2308
- target_species = product.get('Target Species', 'N/A')
2309
- message += f"{format_number_with_emoji(i)} {product_name}\n"
2310
- message += f" 📦 {category} ({target_species})\n\n"
2311
-
2312
- message += (
2313
- f"💬 *To view detailed information about any product, reply with its number (1-{len(products)})*\n"
2314
- "💬 *Type 'main' to return to the main menu*"
2315
- )
2316
-
2317
- # Translate response if needed
2318
- if reply_language == 'ur':
2319
- try:
2320
- translated_message = GoogleTranslator(source='auto', target='ur').translate(message)
2321
- send_whatsjet_message(from_number, translated_message)
2322
- except Exception as e:
2323
- logger.error(f"[AI] Translation error: {e}")
2324
- send_whatsjet_message(from_number, message)
2325
- else:
2326
- send_whatsjet_message(from_number, message)
2327
-
2328
- # Store the product list in context for selection handling
2329
- context_manager.update_context(
2330
- from_number,
2331
- current_state='intelligent_products_menu',
2332
- current_menu='intelligent_products_menu',
2333
- current_menu_options=[f"Product {i+1}" for i in range(len(products))],
2334
- available_products=products,
2335
- last_query=query
2336
- )
2337
-
2338
- # Add to conversation history
2339
- context_manager.add_to_history(from_number, query, message)
2340
-
2341
- else:
2342
- # Single product found - show detailed information as before
2343
  selected_product = products[0]
 
 
2344
  context_manager.update_context(
2345
  from_number,
2346
  current_product=selected_product,
@@ -3685,7 +2919,7 @@ def is_valid_menu_selection(selection: str, current_state: str, user_context: di
3685
  def generate_veterinary_welcome_message(phone_number=None, user_context=None):
3686
  """Generate veterinary welcome message"""
3687
  return (
3688
- "🏥 *Welcome to Apex Biotical Veterinary Bot*\n\n"
3689
  "I'm your intelligent veterinary assistant. How can I help you today?\n\n"
3690
  "📋 *Main Menu:*\n"
3691
  "1️⃣ Search Veterinary Products\n"
 
1
  #!/usr/bin/env python3
2
  """
3
+ Apex Biotical Veterinary WhatsApp Assistant - Premium Edition
4
+ The most effective and accurate veterinary Assistant in the market
5
  """
6
 
7
  import os
 
60
  load_dotenv()
61
 
62
  # Initialize FastAPI app
63
+ app = FastAPI(title="Apex Biotical Veterinary Assistant", version="2.0.0")
64
 
65
  # Ensure static and uploads directories exist before mounting
66
  os.makedirs('static', exist_ok=True)
 
280
  model="whisper-1",
281
  file=audio_file,
282
  language="en", # Force English first
283
+ prompt="This is a voice message for a veterinary products Assistant. Language: English or Urdu only. Common greetings: hi, hello, hey, salam, assalamualaikum. Numbers: one, two, three, 1, 2, 3, aik, do, teen. Menu options: search, browse, download, catalog, product, category, contact, availability, hydropex, heposel, respira aid plus, etc."
284
  )
285
 
286
  transcribed_text = transcript.text.strip()
 
295
  model="whisper-1",
296
  file=audio_file,
297
  language="ur", # Force Urdu
298
+ prompt="This is a voice message in Urdu for a veterinary products Assistant. Common Urdu greetings: سلام, ہیلو, ہائے, السلام علیکم, وعلیکم السلام. Numbers: ایک, دو, تین, چار, پانچ, 1, 2, 3, 4, 5. Menu options: تلاش, براؤز, ڈاؤن لوڈ, کیٹلاگ, پروڈکٹ, کیٹیگری, رابطہ, دستیابی, ہائیڈروپیکس, ہیپوسیل, ریسپیرا ایڈ پلس, وغیرہ."
299
  )
300
 
301
  transcribed_text = transcript.text.strip()
 
309
  transcript = openai.Audio.transcribe(
310
  model="whisper-1",
311
  file=audio_file,
312
+ prompt="This is a voice message for a veterinary products Assistant. Language: English or Urdu only. Common words: hi, hello, salam, one, two, three, aik, do, teen, search, browse, download, catalog, products, categories, contact, availability, hydropex, heposel, respira aid plus, etc."
313
  )
314
 
315
  transcribed_text = transcript.text.strip()
 
1044
  @app.get("/", response_class=HTMLResponse)
1045
  async def root():
1046
  return """
1047
+ <h2>Apex Biotical Veterinary WhatsApp Assistant</h2>
1048
+ <p>The Assistant is running! Use the API endpoints for WhatsApp integration.</p>
1049
+ <ul>
1050
  <h2>Apex Biotical Veterinary WhatsApp Bot</h2>
1051
  <p>The bot is running! Use the API endpoints for WhatsApp integration.</p>
1052
  <ul>
 
1542
  # This ensures users can say product names like "hydropex", "respira aid plus", etc. from any menu
1543
  logger.info(f"[Process] Checking for product name in message: '{message_body}' from state: {current_state}")
1544
  products = get_veterinary_product_matches(message_body)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1545
 
1546
+ # --- NEW LOGIC: Check for exact match first ---
1547
+ normalized_input = normalize(message_body).lower().strip()
1548
+ exact_match = None
1549
+ for product in products:
1550
+ product_name = product.get('Product Name', '')
1551
+ normalized_product_name = normalize(product_name).lower().strip()
1552
+ if normalized_product_name == normalized_input:
1553
+ exact_match = product
1554
+ break
1555
+
1556
+ if exact_match:
1557
+ logger.info(f"[Process] Exact product match found: {exact_match.get('Product Name', 'Unknown')}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1558
  context_manager.update_context(
1559
  from_number,
1560
+ current_product=exact_match,
1561
  current_state='product_inquiry',
1562
  current_menu='product_inquiry',
1563
  current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
1564
  )
1565
+ response = generate_veterinary_product_response(exact_match, user_context)
 
1566
  send_whatsjet_message(from_number, response)
 
 
 
 
 
 
 
 
 
 
 
1567
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1568
 
1569
+ # --- END NEW LOGIC ---
1570
+
 
 
 
 
1571
  if products:
1572
+ logger.info(f"[Process] Product name detected: '{message_body}' -> Found {len(products)} products")
1573
+ # If single product found, show it directly
1574
+ if len(products) == 1:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1575
  selected_product = products[0]
1576
+ product_name = selected_product.get('Product Name', 'Unknown')
1577
+ logger.info(f"[Process] Single product found: {product_name}")
1578
  context_manager.update_context(
1579
  from_number,
1580
  current_product=selected_product,
 
2919
  def generate_veterinary_welcome_message(phone_number=None, user_context=None):
2920
  """Generate veterinary welcome message"""
2921
  return (
2922
+ "🏥 *Welcome to Apex Biotical Veterinary Assistant*\n\n"
2923
  "I'm your intelligent veterinary assistant. How can I help you today?\n\n"
2924
  "📋 *Main Menu:*\n"
2925
  "1️⃣ Search Veterinary Products\n"