DreamStream-1 commited on
Commit
bab45bb
·
verified ·
1 Parent(s): 0c26c18

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +232 -40
app.py CHANGED
@@ -289,19 +289,19 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
289
 
290
  logger.info(f"[Transcribe] Transcribing file: {file_path} (size: {file_size} bytes)")
291
 
292
- # Comprehensive system prompt for veterinary WhatsApp assistant
293
  system_prompt = """
294
  You are transcribing voice messages for Apex Biotical Veterinary WhatsApp Assistant. This is a professional veterinary products chatbot.
295
 
296
- CRITICAL: TRANSCRIBE ONLY ENGLISH OR URDU SPEECH - NOTHING ELSE
297
 
298
  IMPORTANT RULES:
299
  1. ONLY transcribe English or Urdu speech
300
- 2. If you hear unclear audio, transcribe as English
301
- 3. If you hear mixed languages, transcribe as English
302
  4. Never transcribe gibberish or random characters
303
- 5. If audio is unclear, transcribe as "unclear audio"
304
- 6. Keep transcriptions simple and clean
305
 
306
  PRODUCT NAMES (exact spelling required):
307
  - Hydropex, Respira Aid Plus, Heposel, Bromacid, Hexatox
@@ -320,12 +320,12 @@ GREETINGS:
320
  - Urdu: salam, assalamu alaikum, adaab, namaste, khuda hafiz
321
 
322
  TRANSCRIPTION RULES:
323
- 1. Transcribe exactly what you hear in English or Urdu
324
  2. Convert numbers to digits (one->1, two->2, etc.)
325
  3. Preserve product names exactly
326
- 4. If unclear, transcribe as "unclear audio"
327
  5. Keep it simple and clean
328
- 6. No random characters or mixed languages
329
 
330
  EXAMPLES:
331
  - "hydropex" -> "hydropex"
@@ -334,6 +334,7 @@ EXAMPLES:
334
  - "main menu" -> "main"
335
  - "salam" -> "salam"
336
  - "search products" -> "search products"
 
337
  - Unclear audio -> "unclear audio"
338
  """
339
 
@@ -475,6 +476,53 @@ def process_voice_input(text: str) -> str:
475
  # Remove extra whitespace
476
  processed_text = re.sub(r'\s+', ' ', processed_text)
477
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  # Basic punctuation cleanup
479
  processed_text = processed_text.replace(' ,', ',').replace(' .', '.')
480
 
@@ -832,7 +880,10 @@ def generate_veterinary_product_response(product_info: Dict[str, Any], user_cont
832
  def clean_text(text):
833
  if pd.isna(text) or text is None:
834
  return "Not specified"
835
- return str(text).strip()
 
 
 
836
 
837
  # Extract product details
838
  product_name = clean_text(product_info.get('Product Name', ''))
@@ -881,6 +932,8 @@ def clean_text_for_pdf(text: str) -> str:
881
  return "N/A"
882
 
883
  cleaned = str(text)
 
 
884
  # Remove or replace problematic characters for PDF
885
  cleaned = cleaned.replace('â€"', '-').replace('â€"', '"').replace('’', "'")
886
  cleaned = cleaned.replace('“', '"').replace('â€', '"').replace('…', '...')
@@ -1783,7 +1836,7 @@ async def process_incoming_message(from_number: str, msg: dict):
1783
  )
1784
  return
1785
 
1786
- # 🎯 PRIORITY 2: State-specific handling (contact_request, availability_request, ai_chat_mode)
1787
  if current_state == 'contact_request':
1788
  await handle_contact_request_response(from_number, message_body)
1789
  return
@@ -1793,8 +1846,29 @@ async def process_incoming_message(from_number: str, msg: dict):
1793
  elif current_state == 'ai_chat_mode':
1794
  await handle_ai_chat_mode(from_number, message_body, reply_language)
1795
  return
 
 
 
 
1796
 
1797
- # 🎯 PRIORITY 3: Menu selections - check if this is a valid menu selection for current state
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1798
  if current_state in ['main_menu', 'category_selection_menu', 'category_products_menu', 'all_products_menu', 'product_inquiry', 'intelligent_products_menu']:
1799
  # Validate menu selection
1800
  is_valid, error_msg = validate_menu_selection(message_body, current_state, user_context)
@@ -1897,8 +1971,16 @@ async def process_incoming_message(from_number: str, msg: dict):
1897
  await send_product_image_with_caption(from_number, selected_product, user_context)
1898
  return
1899
  else:
1900
- send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
1901
- return
 
 
 
 
 
 
 
 
1902
  return # Exit after handling menu selection
1903
 
1904
  # 🎯 PRIORITY 4: Product names - works from ANY menu state
@@ -2074,10 +2156,11 @@ Response Guidelines:
2074
  else:
2075
  ai_response += "\n\n💬 *Please type 'main' to go to main menu*"
2076
 
2077
- # Translate response if needed
2078
  if reply_language == 'ur':
2079
  try:
2080
- translated_response = GoogleTranslator(source='auto', target='ur').translate(ai_response)
 
2081
  send_whatsjet_message(from_number, translated_response)
2082
  except Exception as e:
2083
  logger.error(f"[AI] Translation error: {e}")
@@ -2104,6 +2187,54 @@ Response Guidelines:
2104
  current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values())
2105
  )
2106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2107
  async def handle_contact_request(from_number: str):
2108
  """Handle contact request"""
2109
  try:
@@ -2613,13 +2744,14 @@ Response:
2613
  else:
2614
  ai_response += "\n\n💬 *Type 'main' to return to main menu*"
2615
 
2616
- # Translate response if needed
2617
  if reply_language == 'ur':
2618
  try:
2619
  # Get all product and category names
2620
  product_names = [str(p.get('Product Name', '')) for p in all_products if p.get('Product Name')]
2621
  category_names = list(set([str(p.get('Category', '')) for p in all_products if p.get('Category')]))
2622
- translated_response = GoogleTranslator(source='auto', target='ur').translate(ai_response)
 
2623
  # Restore English terms
2624
  translated_response = restore_english_terms(translated_response, ai_response, product_names, category_names)
2625
  send_whatsjet_message(from_number, translated_response)
@@ -2836,7 +2968,10 @@ def generate_veterinary_product_response_with_media(product_info: Dict[str, Any]
2836
  def clean_text(text):
2837
  if pd.isna(text) or text is None:
2838
  return "Not specified"
2839
- return str(text).strip()
 
 
 
2840
 
2841
  product_name = clean_text(product_info.get('Product Name', ''))
2842
  product_type = clean_text(product_info.get('Type', ''))
@@ -3487,14 +3622,17 @@ async def handle_voice_message_complete(from_number: str, msg: dict):
3487
  detected_lang = detect(transcribed_text)
3488
  logger.info(f"[Voice] Raw detected language: {detected_lang}")
3489
 
3490
- # STRICTLY ENGLISH OR URDU ONLY - NO OTHER LANGUAGES
3491
- # Only allow English and Urdu, reject everything else
3492
  if detected_lang in ['en', 'ur']:
3493
  reply_language = detected_lang
 
3494
  else:
3495
- # Force any other language to English
3496
  reply_language = 'en'
3497
- logger.warning(f"[Voice] Detected language '{detected_lang}' is not English or Urdu, forcing to English")
 
 
 
3498
 
3499
  # Check if text contains Urdu/Arabic characters or Islamic greetings
3500
  urdu_arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
@@ -3514,11 +3652,12 @@ async def handle_voice_message_complete(from_number: str, msg: dict):
3514
  logger.warning(f"[Voice] Language detection failed: {e}, defaulting to English")
3515
  reply_language = 'en'
3516
 
3517
- # For Urdu voice notes, translate to English for processing
3518
  processing_text = transcribed_text
3519
  if reply_language == 'ur' and detected_lang == 'ur':
3520
  try:
3521
  logger.info(f"[Voice] Translating Urdu voice note to English for processing")
 
3522
  translated_text = GoogleTranslator(source='ur', target='en').translate(transcribed_text)
3523
  processing_text = translated_text
3524
  logger.info(f"[Voice] Translated to English: {translated_text}")
@@ -3526,6 +3665,17 @@ async def handle_voice_message_complete(from_number: str, msg: dict):
3526
  logger.error(f"[Voice] Translation failed: {e}")
3527
  # If translation fails, use original text
3528
  processing_text = transcribed_text
 
 
 
 
 
 
 
 
 
 
 
3529
 
3530
  # Determine reply language - always respond in English or Urdu
3531
  if detected_lang == 'ur':
@@ -3556,13 +3706,14 @@ async def handle_voice_message_complete(from_number: str, msg: dict):
3556
  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()))
3557
  return
3558
 
3559
- # Process the translated text using the same strict state-based logic as text messages
3560
- # This ensures voice messages follow the same menu and state rules as text messages
3561
  await process_incoming_message(from_number, {
3562
  'body': processing_text, # Use translated text for processing
3563
  'type': 'text',
3564
  'reply_language': reply_language,
3565
- 'original_transcription': transcribed_text # Keep original for context
 
3566
  })
3567
 
3568
  except Exception as e:
@@ -3892,10 +4043,11 @@ Format your response professionally with emojis and clear structure. Keep it con
3892
 
3893
  full_response = ai_response + selection_instructions
3894
 
3895
- # Translate response if needed
3896
  if reply_language == 'ur':
3897
  try:
3898
- translated_response = GoogleTranslator(source='auto', target='ur').translate(full_response)
 
3899
  send_whatsjet_message(from_number, translated_response)
3900
  except Exception as e:
3901
  logger.error(f"[AI] Translation error: {e}")
@@ -3937,10 +4089,11 @@ Format your response professionally with emojis and clear structure. Keep it con
3937
  "💬 *Type 'main' to return to the main menu*"
3938
  )
3939
 
3940
- # Translate response if needed
3941
  if reply_language == 'ur':
3942
  try:
3943
- translated_message = GoogleTranslator(source='auto', target='ur').translate(message)
 
3944
  send_whatsjet_message(from_number, translated_message)
3945
  except Exception as e:
3946
  logger.error(f"[AI] Translation error: {e}")
@@ -3974,9 +4127,9 @@ Format your response professionally with emojis and clear structure. Keep it con
3974
 
3975
  # If it's a mode of action query, provide detailed mechanism information
3976
  if is_mode_of_action_query:
3977
- product_name = selected_product.get('Product Name', 'Unknown')
3978
- composition = selected_product.get('Composition', 'Not specified')
3979
- indications = selected_product.get('Indications', 'Not specified')
3980
 
3981
  mode_of_action_response = (
3982
  f"🧪 *{product_name} - Mode of Action*\n\n"
@@ -3997,13 +4150,52 @@ Format your response professionally with emojis and clear structure. Keep it con
3997
  context_manager.add_to_history(from_number, query, f"Product inquiry for {selected_product.get('Product Name', 'Unknown')}")
3998
 
3999
  else:
4000
- # Generic, professional "not found" response
4001
- if reply_language == 'ur':
4002
- message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4003
  else:
4004
- message = " *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
4005
-
4006
- send_whatsjet_message(from_number, message)
 
 
 
 
4007
 
4008
  except Exception as e:
4009
  logger.error(f"Error in product inquiry: {e}")
 
289
 
290
  logger.info(f"[Transcribe] Transcribing file: {file_path} (size: {file_size} bytes)")
291
 
292
+ # Comprehensive system prompt for veterinary WhatsApp assistant - ENGLISH AND URDU ONLY
293
  system_prompt = """
294
  You are transcribing voice messages for Apex Biotical Veterinary WhatsApp Assistant. This is a professional veterinary products chatbot.
295
 
296
+ CRITICAL: TRANSCRIBE ONLY ENGLISH OR URDU SPEECH - REJECT ALL OTHER LANGUAGES
297
 
298
  IMPORTANT RULES:
299
  1. ONLY transcribe English or Urdu speech
300
+ 2. If you hear any other language, transcribe as "unclear audio"
301
+ 3. If you hear unclear audio, transcribe as "unclear audio"
302
  4. Never transcribe gibberish or random characters
303
+ 5. Keep transcriptions simple and clean
304
+ 6. Reject non-English/Urdu languages completely
305
 
306
  PRODUCT NAMES (exact spelling required):
307
  - Hydropex, Respira Aid Plus, Heposel, Bromacid, Hexatox
 
320
  - Urdu: salam, assalamu alaikum, adaab, namaste, khuda hafiz
321
 
322
  TRANSCRIPTION RULES:
323
+ 1. Transcribe exactly what you hear in English or Urdu ONLY
324
  2. Convert numbers to digits (one->1, two->2, etc.)
325
  3. Preserve product names exactly
326
+ 4. If unclear or non-English/Urdu, transcribe as "unclear audio"
327
  5. Keep it simple and clean
328
+ 6. Reject all other languages
329
 
330
  EXAMPLES:
331
  - "hydropex" -> "hydropex"
 
334
  - "main menu" -> "main"
335
  - "salam" -> "salam"
336
  - "search products" -> "search products"
337
+ - Non-English/Urdu speech -> "unclear audio"
338
  - Unclear audio -> "unclear audio"
339
  """
340
 
 
476
  # Remove extra whitespace
477
  processed_text = re.sub(r'\s+', ' ', processed_text)
478
 
479
+ # Fix special characters and encoding issues
480
+ processed_text = clean_special_characters(processed_text)
481
+
482
+ return processed_text
483
+
484
+ def clean_special_characters(text: str) -> str:
485
+ """Clean special characters and fix encoding issues"""
486
+ if not text:
487
+ return text
488
+
489
+ # Fix common encoding issues
490
+ replacements = {
491
+ 'â€"': '–', # Fix en dash
492
+ 'â€"': '—', # Fix em dash
493
+ '’': "'", # Fix apostrophe
494
+ '“': '"', # Fix opening quote
495
+ 'â€': '"', # Fix closing quote
496
+ '…': '...', # Fix ellipsis
497
+ '•': '•', # Fix bullet
498
+ '‰': '°', # Fix degree symbol
499
+ '′': '′', # Fix prime
500
+ '″': '″', # Fix double prime
501
+ '‼': '™', # Fix trademark
502
+ '‮': '®', # Fix registered
503
+ '
': '©', # Fix copyright
504
+ 'â€': '–', # Generic fix for en dash
505
+ 'â€"': '—', # Generic fix for em dash
506
+ '’': "'", # Generic fix for apostrophe
507
+ '“': '"', # Generic fix for opening quote
508
+ 'â€': '"', # Generic fix for closing quote
509
+ '…': '...', # Generic fix for ellipsis
510
+ '•': '•', # Generic fix for bullet
511
+ '‰': '°', # Generic fix for degree symbol
512
+ }
513
+
514
+ # Apply replacements
515
+ for old_char, new_char in replacements.items():
516
+ text = text.replace(old_char, new_char)
517
+
518
+ # Remove any remaining problematic characters
519
+ text = re.sub(r'â€[^"]*', '', text) # Remove any remaining †patterns
520
+
521
+ # Clean up multiple spaces
522
+ text = re.sub(r'\s+', ' ', text)
523
+
524
+ return text.strip()
525
+
526
  # Basic punctuation cleanup
527
  processed_text = processed_text.replace(' ,', ',').replace(' .', '.')
528
 
 
880
  def clean_text(text):
881
  if pd.isna(text) or text is None:
882
  return "Not specified"
883
+ cleaned = str(text).strip()
884
+ # Apply special character cleaning
885
+ cleaned = clean_special_characters(cleaned)
886
+ return cleaned
887
 
888
  # Extract product details
889
  product_name = clean_text(product_info.get('Product Name', ''))
 
932
  return "N/A"
933
 
934
  cleaned = str(text)
935
+ # Apply special character cleaning first
936
+ cleaned = clean_special_characters(cleaned)
937
  # Remove or replace problematic characters for PDF
938
  cleaned = cleaned.replace('â€"', '-').replace('â€"', '"').replace('’', "'")
939
  cleaned = cleaned.replace('“', '"').replace('â€', '"').replace('…', '...')
 
1836
  )
1837
  return
1838
 
1839
+ # 🎯 PRIORITY 2: State-specific handling (contact_request, availability_request, ai_chat_mode, clarification)
1840
  if current_state == 'contact_request':
1841
  await handle_contact_request_response(from_number, message_body)
1842
  return
 
1846
  elif current_state == 'ai_chat_mode':
1847
  await handle_ai_chat_mode(from_number, message_body, reply_language)
1848
  return
1849
+ elif user_context.get('awaiting_clarification', False):
1850
+ # Handle clarification responses
1851
+ await handle_clarification_response(from_number, message_body, user_context)
1852
+ return
1853
 
1854
+ # 🎯 PRIORITY 3: Intelligent product queries from any menu state
1855
+ # Check if the message is about a product from CSV, regardless of current menu
1856
+ products = get_veterinary_product_matches(message_body)
1857
+
1858
+ if products:
1859
+ logger.info(f"[Process] Product query detected from menu state '{current_state}': '{message_body}' -> Found {len(products)} products")
1860
+
1861
+ # If user is in a specific menu but asks about a product, handle it intelligently
1862
+ if current_state in ['main_menu', 'category_selection_menu', 'category_products_menu', 'all_products_menu', 'product_inquiry', 'intelligent_products_menu']:
1863
+ # Use intelligent product inquiry to handle the product query
1864
+ await handle_intelligent_product_inquiry(from_number, message_body, user_context, reply_language)
1865
+ return
1866
+ else:
1867
+ # For other menu states, still handle product queries but remind about menu context
1868
+ await handle_intelligent_product_inquiry(from_number, message_body, user_context, reply_language)
1869
+ return
1870
+
1871
+ # 🎯 PRIORITY 4: Menu selections - check if this is a valid menu selection for current state
1872
  if current_state in ['main_menu', 'category_selection_menu', 'category_products_menu', 'all_products_menu', 'product_inquiry', 'intelligent_products_menu']:
1873
  # Validate menu selection
1874
  is_valid, error_msg = validate_menu_selection(message_body, current_state, user_context)
 
1971
  await send_product_image_with_caption(from_number, selected_product, user_context)
1972
  return
1973
  else:
1974
+ # Check if the invalid input might be a product query
1975
+ products = get_veterinary_product_matches(message_body)
1976
+ if products:
1977
+ logger.info(f"[Process] Invalid menu selection but product found: '{message_body}' -> Handling as product query")
1978
+ await handle_intelligent_product_inquiry(from_number, message_body, user_context, reply_language)
1979
+ return
1980
+ else:
1981
+ # Show menu validation message with guidance
1982
+ send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
1983
+ return
1984
  return # Exit after handling menu selection
1985
 
1986
  # 🎯 PRIORITY 4: Product names - works from ANY menu state
 
2156
  else:
2157
  ai_response += "\n\n💬 *Please type 'main' to go to main menu*"
2158
 
2159
+ # Translate response if needed (ENGLISH/URDU ONLY)
2160
  if reply_language == 'ur':
2161
  try:
2162
+ # Only translate from English to Urdu - no other languages
2163
+ translated_response = GoogleTranslator(source='en', target='ur').translate(ai_response)
2164
  send_whatsjet_message(from_number, translated_response)
2165
  except Exception as e:
2166
  logger.error(f"[AI] Translation error: {e}")
 
2187
  current_menu_options=list(MENU_CONFIG['main_menu']['option_descriptions'].values())
2188
  )
2189
 
2190
+ async def handle_clarification_response(from_number: str, response: str, user_context: dict):
2191
+ """Handle user response to clarification questions"""
2192
+ try:
2193
+ clean_response = response.strip().lower()
2194
+
2195
+ if clean_response in ['yes', 'y', 'apex', 'apex biotical', 'apex biotical solution']:
2196
+ # User confirmed they want Apex Biotical
2197
+ clarification_product = user_context.get('clarification_product', 'apex biotical')
2198
+
2199
+ # Search for the product
2200
+ products = get_veterinary_product_matches(clarification_product)
2201
+
2202
+ if products:
2203
+ # Found the product - show detailed information
2204
+ product = products[0]
2205
+ await send_product_with_image(from_number, product, user_context)
2206
+
2207
+ # Update context
2208
+ user_context['current_product'] = product
2209
+ user_context['current_state'] = 'product_detail'
2210
+ user_context['awaiting_clarification'] = False
2211
+ user_context.pop('clarification_product', None)
2212
+ context_manager.update_context(from_number, **user_context)
2213
+ else:
2214
+ # Product not found even after clarification
2215
+ send_whatsjet_message(from_number, "❌ *Product not found. Please type 'main' to go to main menu.*")
2216
+ user_context['awaiting_clarification'] = False
2217
+ user_context.pop('clarification_product', None)
2218
+ context_manager.update_context(from_number, **user_context)
2219
+ else:
2220
+ # User didn't confirm - use OpenAI for intelligent response
2221
+ if OPENAI_API_KEY:
2222
+ await handle_ai_chat_mode(from_number, response, 'en')
2223
+ else:
2224
+ send_whatsjet_message(from_number, "💬 *Type 'main' to go to main menu or ask another question.*")
2225
+
2226
+ # Clear clarification context
2227
+ user_context['awaiting_clarification'] = False
2228
+ user_context.pop('clarification_product', None)
2229
+ context_manager.update_context(from_number, **user_context)
2230
+
2231
+ except Exception as e:
2232
+ logger.error(f"[Clarification] Error: {str(e)}")
2233
+ send_whatsjet_message(from_number, "❌ *An error occurred. Please type 'main' to go to main menu.*")
2234
+ user_context['awaiting_clarification'] = False
2235
+ user_context.pop('clarification_product', None)
2236
+ context_manager.update_context(from_number, **user_context)
2237
+
2238
  async def handle_contact_request(from_number: str):
2239
  """Handle contact request"""
2240
  try:
 
2744
  else:
2745
  ai_response += "\n\n💬 *Type 'main' to return to main menu*"
2746
 
2747
+ # Translate response if needed (ENGLISH/URDU ONLY)
2748
  if reply_language == 'ur':
2749
  try:
2750
  # Get all product and category names
2751
  product_names = [str(p.get('Product Name', '')) for p in all_products if p.get('Product Name')]
2752
  category_names = list(set([str(p.get('Category', '')) for p in all_products if p.get('Category')]))
2753
+ # Only translate from English to Urdu - no other languages
2754
+ translated_response = GoogleTranslator(source='en', target='ur').translate(ai_response)
2755
  # Restore English terms
2756
  translated_response = restore_english_terms(translated_response, ai_response, product_names, category_names)
2757
  send_whatsjet_message(from_number, translated_response)
 
2968
  def clean_text(text):
2969
  if pd.isna(text) or text is None:
2970
  return "Not specified"
2971
+ cleaned = str(text).strip()
2972
+ # Apply special character cleaning
2973
+ cleaned = clean_special_characters(cleaned)
2974
+ return cleaned
2975
 
2976
  product_name = clean_text(product_info.get('Product Name', ''))
2977
  product_type = clean_text(product_info.get('Type', ''))
 
3622
  detected_lang = detect(transcribed_text)
3623
  logger.info(f"[Voice] Raw detected language: {detected_lang}")
3624
 
3625
+ # STRICTLY ENGLISH OR URDU ONLY - REJECT ALL OTHER LANGUAGES
 
3626
  if detected_lang in ['en', 'ur']:
3627
  reply_language = detected_lang
3628
+ logger.info(f"[Voice] Valid language detected: {detected_lang}")
3629
  else:
3630
+ # Reject any other language and force to English
3631
  reply_language = 'en'
3632
+ logger.warning(f"[Voice] Invalid language '{detected_lang}' detected - forcing to English")
3633
+ # If it's clearly not English/Urdu, mark as unclear
3634
+ if detected_lang not in ['en', 'ur', 'unknown']:
3635
+ logger.warning(f"[Voice] Non-English/Urdu language detected: {detected_lang}")
3636
 
3637
  # Check if text contains Urdu/Arabic characters or Islamic greetings
3638
  urdu_arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
 
3652
  logger.warning(f"[Voice] Language detection failed: {e}, defaulting to English")
3653
  reply_language = 'en'
3654
 
3655
+ # For Urdu voice notes, translate to English for processing (ENGLISH/URDU ONLY)
3656
  processing_text = transcribed_text
3657
  if reply_language == 'ur' and detected_lang == 'ur':
3658
  try:
3659
  logger.info(f"[Voice] Translating Urdu voice note to English for processing")
3660
+ # Only translate from Urdu to English - no other languages
3661
  translated_text = GoogleTranslator(source='ur', target='en').translate(transcribed_text)
3662
  processing_text = translated_text
3663
  logger.info(f"[Voice] Translated to English: {translated_text}")
 
3665
  logger.error(f"[Voice] Translation failed: {e}")
3666
  # If translation fails, use original text
3667
  processing_text = transcribed_text
3668
+ elif detected_lang not in ['en', 'ur']:
3669
+ # If language is not English or Urdu, reject it
3670
+ logger.warning(f"[Voice] Non-English/Urdu language detected: {detected_lang}")
3671
+ send_whatsjet_message(from_number,
3672
+ "🎤 *Voice Message Issue*\n\n"
3673
+ "I can only process voice messages in English or Urdu.\n\n"
3674
+ "💡 *Please:*\n"
3675
+ "• Speak in English or Urdu only\n"
3676
+ "• Send a text message instead\n"
3677
+ "• Type 'main' to see menu options")
3678
+ return
3679
 
3680
  # Determine reply language - always respond in English or Urdu
3681
  if detected_lang == 'ur':
 
3706
  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()))
3707
  return
3708
 
3709
+ # Process the transcribed text using the same intelligent system as text messages
3710
+ # This ensures voice messages get the same intelligent clarification and product search
3711
  await process_incoming_message(from_number, {
3712
  'body': processing_text, # Use translated text for processing
3713
  'type': 'text',
3714
  'reply_language': reply_language,
3715
+ 'original_transcription': transcribed_text, # Keep original for context
3716
+ 'is_voice_message': True # Flag to indicate this came from voice
3717
  })
3718
 
3719
  except Exception as e:
 
4043
 
4044
  full_response = ai_response + selection_instructions
4045
 
4046
+ # Translate response if needed (ENGLISH/URDU ONLY)
4047
  if reply_language == 'ur':
4048
  try:
4049
+ # Only translate from English to Urdu - no other languages
4050
+ translated_response = GoogleTranslator(source='en', target='ur').translate(full_response)
4051
  send_whatsjet_message(from_number, translated_response)
4052
  except Exception as e:
4053
  logger.error(f"[AI] Translation error: {e}")
 
4089
  "💬 *Type 'main' to return to the main menu*"
4090
  )
4091
 
4092
+ # Translate response if needed (ENGLISH/URDU ONLY)
4093
  if reply_language == 'ur':
4094
  try:
4095
+ # Only translate from English to Urdu - no other languages
4096
+ translated_message = GoogleTranslator(source='en', target='ur').translate(message)
4097
  send_whatsjet_message(from_number, translated_message)
4098
  except Exception as e:
4099
  logger.error(f"[AI] Translation error: {e}")
 
4127
 
4128
  # If it's a mode of action query, provide detailed mechanism information
4129
  if is_mode_of_action_query:
4130
+ product_name = clean_special_characters(selected_product.get('Product Name', 'Unknown'))
4131
+ composition = clean_special_characters(selected_product.get('Composition', 'Not specified'))
4132
+ indications = clean_special_characters(selected_product.get('Indications', 'Not specified'))
4133
 
4134
  mode_of_action_response = (
4135
  f"🧪 *{product_name} - Mode of Action*\n\n"
 
4150
  context_manager.add_to_history(from_number, query, f"Product inquiry for {selected_product.get('Product Name', 'Unknown')}")
4151
 
4152
  else:
4153
+ # No products found - check if it's an ambiguous query that needs clarification
4154
+ if any(keyword in clean_query for keyword in ['what is', 'apex', 'immune', 'hydro', 'hepo', 'brom', 'trib', 'symo']):
4155
+ # Check if it might be about a product but needs clarification
4156
+ if 'apex' in clean_query:
4157
+ clarification_message = (
4158
+ "🤔 *I found a similar product in our database.*\n\n"
4159
+ "Are you asking about:\n"
4160
+ "• Apex Biotical Solution\n"
4161
+ "• Or something else?\n\n"
4162
+ "💬 *Type 'yes' to continue with Apex Biotical, or specify what you mean.*"
4163
+ )
4164
+ send_whatsjet_message(from_number, clarification_message)
4165
+ user_context['awaiting_clarification'] = True
4166
+ user_context['clarification_product'] = 'apex biotical'
4167
+ context_manager.update_context(from_number, **user_context)
4168
+ return
4169
+ elif any(product_hint in clean_query for product_hint in ['immune', 'hydro', 'hepo', 'brom', 'trib', 'symo']):
4170
+ # Use OpenAI for intelligent response about veterinary topics
4171
+ if OPENAI_API_KEY:
4172
+ await handle_ai_chat_mode(from_number, query, reply_language)
4173
+ else:
4174
+ # Fallback to generic response
4175
+ if reply_language == 'ur':
4176
+ message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
4177
+ else:
4178
+ message = "❌ *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
4179
+ send_whatsjet_message(from_number, message)
4180
+ else:
4181
+ # Use OpenAI for general veterinary questions
4182
+ if OPENAI_API_KEY:
4183
+ await handle_ai_chat_mode(from_number, query, reply_language)
4184
+ else:
4185
+ # Fallback to generic response
4186
+ if reply_language == 'ur':
4187
+ message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
4188
+ else:
4189
+ message = "❌ *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
4190
+ send_whatsjet_message(from_number, message)
4191
  else:
4192
+ # Generic, professional "not found" response
4193
+ if reply_language == 'ur':
4194
+ message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
4195
+ else:
4196
+ message = "❌ *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
4197
+
4198
+ send_whatsjet_message(from_number, message)
4199
 
4200
  except Exception as e:
4201
  logger.error(f"Error in product inquiry: {e}")