Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -600,6 +600,19 @@ def get_veterinary_product_matches(query: str) -> List[Dict[str, Any]]:
|
|
600 |
logger.info(f"[Veterinary Search] Skipping menu selection: '{normalized_query}'")
|
601 |
return []
|
602 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
603 |
scored_matches = []
|
604 |
|
605 |
# Veterinary-specific query expansion
|
@@ -620,27 +633,29 @@ def get_veterinary_product_matches(query: str) -> List[Dict[str, Any]]:
|
|
620 |
if category_key in normalized_query:
|
621 |
expanded_queries.extend(categories)
|
622 |
|
623 |
-
#
|
624 |
veterinary_variations = {
|
625 |
-
'hydropex': ['hydropex', 'hydro pex', 'electrolyte', 'dehydration', 'heat stress'],
|
626 |
-
'heposel': ['heposel', 'hepo sel', 'liver tonic', 'hepatoprotective'],
|
627 |
-
'bromacid': ['bromacid', 'brom acid', 'respiratory', 'mucolytic'],
|
628 |
-
'respira aid': ['respira aid', 'respira aid plus', 'respiratory support'],
|
629 |
-
'hexatox': ['hexatox', 'hexa tox', 'liver support', 'kidney support'],
|
630 |
-
'apma fort': ['apma fort', 'mycotoxin', 'liver support'],
|
631 |
-
'para c': ['para c', 'para c.e', 'heat stress', 'paracetamol'],
|
632 |
'tribiotic': ['tribiotic', 'antibiotic', 'respiratory infection'],
|
633 |
-
'phyto-sal': ['phyto-sal', 'phytogenic', 'vitamin supplement'],
|
634 |
-
'mycopex': ['mycopex', 'mycotoxin binder', 'mold'],
|
635 |
-
'oftilex': ['oftilex', 'ofloxacin', 'antibiotic'],
|
636 |
-
'biscomin': ['biscomin', 'oxytetracycline', 'injectable'],
|
637 |
-
'apvita': ['apvita', 'vitamin b', 'amino acid'],
|
638 |
-
'bg aspro': ['bg aspro', 'aspirin', 'vitamin c'],
|
639 |
-
'ec-immune': ['ec-immune', 'immune', 'immunity'],
|
640 |
'liverpex': ['liverpex', 'liver', 'metabolic'],
|
641 |
'symodex': ['symodex', 'multivitamin', 'vitamin'],
|
642 |
-
'adek gold': ['adek gold', 'vitamin', 'multivitamin'],
|
643 |
-
'immuno dx': ['immuno dx', 'immune', 'antioxidant']
|
|
|
|
|
644 |
}
|
645 |
|
646 |
# Add veterinary variations
|
@@ -678,11 +693,11 @@ def get_veterinary_product_matches(query: str) -> List[Dict[str, Any]]:
|
|
678 |
best_match_type = "exact"
|
679 |
match_details = {"field": field_name, "query": expanded_query}
|
680 |
|
681 |
-
# Fuzzy matching for close matches
|
682 |
for expanded_query in expanded_queries:
|
683 |
if len(expanded_query) > 3: # Only fuzzy match longer queries
|
684 |
score = fuzz.partial_ratio(normalized_query, field_str) * weight
|
685 |
-
if score > best_score and score >
|
686 |
best_score = score
|
687 |
best_match_type = "fuzzy"
|
688 |
match_details = {"field": field_name, "query": expanded_query}
|
@@ -1955,37 +1970,9 @@ async def process_incoming_message(from_number: str, msg: dict):
|
|
1955 |
return
|
1956 |
|
1957 |
else:
|
1958 |
-
#
|
1959 |
-
|
1960 |
-
|
1961 |
-
f"🔍 *We couldn't find '{message_body}' in our veterinary database.*\n\n"
|
1962 |
-
"💡 *Try these alternatives:*\n"
|
1963 |
-
"• Check spelling (e.g., 'Hydropex' not 'Hydro pex')\n"
|
1964 |
-
"• Search by symptoms (e.g., 'respiratory', 'liver support')\n"
|
1965 |
-
"• Search by category (e.g., 'antibiotic', 'vitamin')\n"
|
1966 |
-
"• Search by species (e.g., 'poultry', 'livestock')\n\n"
|
1967 |
-
"🏥 *Popular Veterinary Products:*\n"
|
1968 |
-
"• Hydropex (Electrolyte supplement)\n"
|
1969 |
-
"• Heposel (Liver tonic)\n"
|
1970 |
-
"• Bromacid (Respiratory support)\n"
|
1971 |
-
"• Tribiotic (Antibiotic)\n"
|
1972 |
-
"• Symodex (Multivitamin)\n\n"
|
1973 |
-
"💬 *Type 'main' to return to main menu or try another search.*"
|
1974 |
-
)
|
1975 |
-
|
1976 |
-
# Translate response if needed
|
1977 |
-
if reply_language == 'ur':
|
1978 |
-
try:
|
1979 |
-
translated_message = GoogleTranslator(source='auto', target='ur').translate(message)
|
1980 |
-
send_whatsjet_message(from_number, translated_message)
|
1981 |
-
except Exception as e:
|
1982 |
-
logger.error(f"[AI] Translation error: {e}")
|
1983 |
-
send_whatsjet_message(from_number, message)
|
1984 |
-
else:
|
1985 |
-
send_whatsjet_message(from_number, message)
|
1986 |
-
|
1987 |
-
# 🎯 PRIORITY 5: Default: treat as general query with intelligent product inquiry
|
1988 |
-
await handle_intelligent_product_inquiry(from_number, message_body, user_context, reply_language)
|
1989 |
|
1990 |
except Exception as e:
|
1991 |
logger.error(f"Error in process_incoming_message: {e}")
|
@@ -2001,20 +1988,50 @@ async def handle_general_query_with_ai(from_number: str, query: str, user_contex
|
|
2001 |
logger.info(f"[AI General] Forcing reply_language to Urdu for Option 4.")
|
2002 |
|
2003 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004 |
if not OPENAI_API_KEY:
|
2005 |
-
|
2006 |
-
|
|
|
|
|
|
|
|
|
2007 |
return
|
2008 |
|
2009 |
# Create context-aware prompt
|
2010 |
current_state = user_context.get('current_state', 'main_menu')
|
2011 |
current_product = user_context.get('current_product')
|
2012 |
|
2013 |
-
#
|
2014 |
-
|
2015 |
-
|
2016 |
-
|
2017 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018 |
prompt = f"""
|
2019 |
You are a professional veterinary product assistant for Apex Biotical, helping users on WhatsApp.
|
2020 |
Always answer in a clear, accurate, and helpful manner.
|
@@ -2023,21 +2040,40 @@ User Query: "{query}"
|
|
2023 |
Current State: {current_state}
|
2024 |
Current Product: {current_product.get('Product Name', 'None') if current_product else 'None'}
|
2025 |
|
2026 |
-
|
2027 |
-
|
2028 |
-
|
2029 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2030 |
"""
|
2031 |
|
2032 |
response = openai.ChatCompletion.create(
|
2033 |
model="gpt-4o",
|
2034 |
messages=[{"role": "user", "content": prompt}],
|
2035 |
temperature=0.7,
|
2036 |
-
max_tokens=
|
2037 |
)
|
2038 |
|
2039 |
ai_response = response.choices[0].message.content.strip()
|
2040 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2041 |
# Translate response if needed
|
2042 |
if reply_language == 'ur':
|
2043 |
try:
|
@@ -2054,9 +2090,13 @@ Always keep responses professional, concise, and user-friendly.
|
|
2054 |
|
2055 |
except Exception as e:
|
2056 |
logger.error(f"[AI] Error handling general query: {e}")
|
2057 |
-
#
|
2058 |
-
|
2059 |
-
|
|
|
|
|
|
|
|
|
2060 |
context_manager.update_context(
|
2061 |
from_number,
|
2062 |
current_state='main_menu',
|
@@ -3714,9 +3754,96 @@ async def test_send_product_image(phone: str, product_name: str = "Bromacid"):
|
|
3714 |
async def handle_intelligent_product_inquiry(from_number: str, query: str, user_context: dict, reply_language: str = 'en'):
|
3715 |
"""Handle product inquiry with OpenAI intelligence and media support"""
|
3716 |
try:
|
3717 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3718 |
products = get_veterinary_product_matches(query)
|
3719 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3720 |
if products:
|
3721 |
# Check if this is a broad/category query (multiple products found)
|
3722 |
if len(products) > 1:
|
@@ -3845,47 +3972,48 @@ Format your response professionally with emojis and clear structure. Keep it con
|
|
3845 |
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
3846 |
)
|
3847 |
|
3848 |
-
#
|
3849 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3850 |
|
3851 |
# Add to conversation history
|
3852 |
context_manager.add_to_history(from_number, query, f"Product inquiry for {selected_product.get('Product Name', 'Unknown')}")
|
3853 |
|
3854 |
else:
|
3855 |
-
#
|
3856 |
-
message = (
|
3857 |
-
"❌ *Product Not Found*\n\n"
|
3858 |
-
f"🔍 *We couldn't find '{query}' in our veterinary database.*\n\n"
|
3859 |
-
"💡 *Try these alternatives:*\n"
|
3860 |
-
"• Check spelling (e.g., 'Hydropex' not 'Hydro pex')\n"
|
3861 |
-
"• Search by symptoms (e.g., 'respiratory', 'liver support')\n"
|
3862 |
-
"• Search by category (e.g., 'antibiotic', 'vitamin')\n"
|
3863 |
-
"• Search by species (e.g., 'poultry', 'livestock')\n\n"
|
3864 |
-
"🏥 *Popular Veterinary Products:*\n"
|
3865 |
-
"• Hydropex (Electrolyte supplement)\n"
|
3866 |
-
"• Heposel (Liver tonic)\n"
|
3867 |
-
"• Bromacid (Respiratory support)\n"
|
3868 |
-
"• Tribiotic (Antibiotic)\n"
|
3869 |
-
"• Symodex (Multivitamin)\n\n"
|
3870 |
-
"💬 *Type 'main' to return to main menu or try another search.*"
|
3871 |
-
)
|
3872 |
-
|
3873 |
-
# Translate response if needed
|
3874 |
if reply_language == 'ur':
|
3875 |
-
|
3876 |
-
translated_message = GoogleTranslator(source='auto', target='ur').translate(message)
|
3877 |
-
send_whatsjet_message(from_number, translated_message)
|
3878 |
-
except Exception as e:
|
3879 |
-
logger.error(f"[AI] Translation error: {e}")
|
3880 |
-
send_whatsjet_message(from_number, message)
|
3881 |
else:
|
3882 |
-
|
|
|
|
|
3883 |
|
3884 |
except Exception as e:
|
3885 |
logger.error(f"Error in product inquiry: {e}")
|
3886 |
-
#
|
3887 |
-
|
3888 |
-
|
|
|
|
|
|
|
|
|
3889 |
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()))
|
3890 |
|
3891 |
async def handle_contact_request(from_number: str):
|
|
|
600 |
logger.info(f"[Veterinary Search] Skipping menu selection: '{normalized_query}'")
|
601 |
return []
|
602 |
|
603 |
+
# Check if this is a mode of action query
|
604 |
+
mode_of_action_keywords = ['mode of action', 'mechanism', 'how does it work', 'what does it do', 'how it works', 'mood of action']
|
605 |
+
is_mode_of_action_query = any(keyword in normalized_query for keyword in mode_of_action_keywords)
|
606 |
+
|
607 |
+
# Extract product name from mode of action query
|
608 |
+
if is_mode_of_action_query:
|
609 |
+
# Try to extract product name from the query
|
610 |
+
for _, row in products_df.iterrows():
|
611 |
+
product_name = str(row.get('Product Name', '')).lower()
|
612 |
+
if product_name in normalized_query:
|
613 |
+
logger.info(f"[Veterinary Search] Mode of action query for product: {product_name}")
|
614 |
+
return [row.to_dict()]
|
615 |
+
|
616 |
scored_matches = []
|
617 |
|
618 |
# Veterinary-specific query expansion
|
|
|
633 |
if category_key in normalized_query:
|
634 |
expanded_queries.extend(categories)
|
635 |
|
636 |
+
# Enhanced veterinary product variations with more variations
|
637 |
veterinary_variations = {
|
638 |
+
'hydropex': ['hydropex', 'hydro pex', 'hydropex', 'electrolyte', 'dehydration', 'heat stress'],
|
639 |
+
'heposel': ['heposel', 'hepo sel', 'heposel', 'liver tonic', 'hepatoprotective'],
|
640 |
+
'bromacid': ['bromacid', 'brom acid', 'bromacid', 'respiratory', 'mucolytic'],
|
641 |
+
'respira aid': ['respira aid', 'respira aid plus', 'respiraaid', 'respiratory support'],
|
642 |
+
'hexatox': ['hexatox', 'hexa tox', 'hexatox', 'liver support', 'kidney support'],
|
643 |
+
'apma fort': ['apma fort', 'apmafort', 'mycotoxin', 'liver support'],
|
644 |
+
'para c': ['para c', 'para c.e', 'parace', 'heat stress', 'paracetamol'],
|
645 |
'tribiotic': ['tribiotic', 'antibiotic', 'respiratory infection'],
|
646 |
+
'phyto-sal': ['phyto-sal', 'phytosal', 'phytogenic', 'vitamin supplement'],
|
647 |
+
'mycopex': ['mycopex', 'mycopex super', 'mycotoxin binder', 'mold'],
|
648 |
+
'oftilex': ['oftilex', 'oftilex ua-10', 'ofloxacin', 'antibiotic'],
|
649 |
+
'biscomin': ['biscomin', 'biscomin 10', 'oxytetracycline', 'injectable'],
|
650 |
+
'apvita': ['apvita', 'apvita plus', 'vitamin b', 'amino acid'],
|
651 |
+
'bg aspro': ['bg aspro', 'b-g aspro-c', 'aspirin', 'vitamin c'],
|
652 |
+
'ec-immune': ['ec-immune', 'ec immune', 'ecimmune', 'immune', 'immunity'],
|
653 |
'liverpex': ['liverpex', 'liver', 'metabolic'],
|
654 |
'symodex': ['symodex', 'multivitamin', 'vitamin'],
|
655 |
+
'adek gold': ['adek gold', 'adekgold', 'vitamin', 'multivitamin'],
|
656 |
+
'immuno dx': ['immuno dx', 'immunodx', 'immune', 'antioxidant'],
|
657 |
+
'apex': ['apex', 'aapex', 'apex biotical'],
|
658 |
+
'apex biotical': ['apex biotical', 'apex', 'aapex']
|
659 |
}
|
660 |
|
661 |
# Add veterinary variations
|
|
|
693 |
best_match_type = "exact"
|
694 |
match_details = {"field": field_name, "query": expanded_query}
|
695 |
|
696 |
+
# Fuzzy matching for close matches (improved threshold)
|
697 |
for expanded_query in expanded_queries:
|
698 |
if len(expanded_query) > 3: # Only fuzzy match longer queries
|
699 |
score = fuzz.partial_ratio(normalized_query, field_str) * weight
|
700 |
+
if score > best_score and score > 75: # Increased threshold for better accuracy
|
701 |
best_score = score
|
702 |
best_match_type = "fuzzy"
|
703 |
match_details = {"field": field_name, "query": expanded_query}
|
|
|
1970 |
return
|
1971 |
|
1972 |
else:
|
1973 |
+
# Use intelligent product inquiry for all non-found queries
|
1974 |
+
await handle_intelligent_product_inquiry(from_number, message_body, user_context, reply_language)
|
1975 |
+
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1976 |
|
1977 |
except Exception as e:
|
1978 |
logger.error(f"Error in process_incoming_message: {e}")
|
|
|
1988 |
logger.info(f"[AI General] Forcing reply_language to Urdu for Option 4.")
|
1989 |
|
1990 |
try:
|
1991 |
+
# Check if this is a non-product query that should get a simple response
|
1992 |
+
non_product_keywords = ['what is', 'who are', 'where is', 'when', 'why', 'how to', 'can you', 'do you', 'is this', 'are you']
|
1993 |
+
is_simple_query = any(keyword in query.lower() for keyword in non_product_keywords)
|
1994 |
+
|
1995 |
+
# Check for company-related queries
|
1996 |
+
company_queries = ['apex', 'aapex', 'apex biotical', 'company', 'about', 'who are you', 'what are you']
|
1997 |
+
is_company_query = any(keyword in query.lower() for keyword in company_queries)
|
1998 |
+
|
1999 |
+
if is_company_query:
|
2000 |
+
if reply_language == 'ur':
|
2001 |
+
response = "🏥 *Apex Biotical Solutions*\n\nہم ایک پیشہ ور ویٹرنری پروڈکٹس کمپنی ہیں۔\n\n💬 *براہ کرم 'main' لکھ کر مین مینو پر جائیں*"
|
2002 |
+
else:
|
2003 |
+
response = "🏥 *Apex Biotical Solutions*\n\nWe are a professional veterinary products company.\n\n💬 *Please type 'main' to go to main menu*"
|
2004 |
+
send_whatsjet_message(from_number, response)
|
2005 |
+
return
|
2006 |
+
|
2007 |
if not OPENAI_API_KEY:
|
2008 |
+
if reply_language == 'ur':
|
2009 |
+
send_whatsjet_message(from_number,
|
2010 |
+
"❌ *AI assistance دستیاب نہیں ہے*\n\n💬 *براہ کرم 'main' لکھ کر مین مینو پر جائیں*")
|
2011 |
+
else:
|
2012 |
+
send_whatsjet_message(from_number,
|
2013 |
+
"❌ AI assistance is not available. Please type 'main' for the menu.")
|
2014 |
return
|
2015 |
|
2016 |
# Create context-aware prompt
|
2017 |
current_state = user_context.get('current_state', 'main_menu')
|
2018 |
current_product = user_context.get('current_product')
|
2019 |
|
2020 |
+
# Get all products data for context
|
2021 |
+
all_products = []
|
2022 |
+
if products_df is not None and not products_df.empty:
|
2023 |
+
all_products = products_df.to_dict('records')
|
2024 |
+
|
2025 |
+
# Create comprehensive context for AI
|
2026 |
+
products_context = ""
|
2027 |
+
if all_products:
|
2028 |
+
products_context = "Available Veterinary Products:\n"
|
2029 |
+
for i, product in enumerate(all_products[:30], 1): # Limit to first 30 products for context
|
2030 |
+
product_name = product.get('Product Name', 'N/A')
|
2031 |
+
category = product.get('Category', 'N/A')
|
2032 |
+
products_context += f"{i}. {product_name} - {category}\n"
|
2033 |
+
|
2034 |
+
# Enhanced prompt for better responses
|
2035 |
prompt = f"""
|
2036 |
You are a professional veterinary product assistant for Apex Biotical, helping users on WhatsApp.
|
2037 |
Always answer in a clear, accurate, and helpful manner.
|
|
|
2040 |
Current State: {current_state}
|
2041 |
Current Product: {current_product.get('Product Name', 'None') if current_product else 'None'}
|
2042 |
|
2043 |
+
Available Products:
|
2044 |
+
{products_context}
|
2045 |
+
|
2046 |
+
IMPORTANT RULES:
|
2047 |
+
1. If the user asks about products, list relevant products with brief descriptions
|
2048 |
+
2. If the user asks general veterinary questions, provide concise, expert answers
|
2049 |
+
3. If the query is unclear or not related to veterinary products, politely redirect to main menu
|
2050 |
+
4. Keep responses professional, concise, and user-friendly
|
2051 |
+
5. Always end with instructions to type 'main' to return to main menu
|
2052 |
+
6. If the query seems like a test or unrelated question, provide a simple redirect response
|
2053 |
+
|
2054 |
+
Response Guidelines:
|
2055 |
+
- Be professional and helpful
|
2056 |
+
- Keep responses concise (max 3-4 sentences)
|
2057 |
+
- Always include menu navigation instructions
|
2058 |
+
- If unsure, redirect to main menu
|
2059 |
"""
|
2060 |
|
2061 |
response = openai.ChatCompletion.create(
|
2062 |
model="gpt-4o",
|
2063 |
messages=[{"role": "user", "content": prompt}],
|
2064 |
temperature=0.7,
|
2065 |
+
max_tokens=200 # Reduced for more concise responses
|
2066 |
)
|
2067 |
|
2068 |
ai_response = response.choices[0].message.content.strip()
|
2069 |
|
2070 |
+
# Ensure the response includes navigation instructions
|
2071 |
+
if 'main' not in ai_response.lower():
|
2072 |
+
if reply_language == 'ur':
|
2073 |
+
ai_response += "\n\n💬 *براہ کرم 'main' لکھ کر مین مینو پر جائیں*"
|
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:
|
|
|
2090 |
|
2091 |
except Exception as e:
|
2092 |
logger.error(f"[AI] Error handling general query: {e}")
|
2093 |
+
# Professional error response
|
2094 |
+
if reply_language == 'ur':
|
2095 |
+
error_msg = "❌ *خطا آ گئی ہے*\n\n💬 *براہ کرم 'main' لکھ کر مین مینو پر جائیں*"
|
2096 |
+
else:
|
2097 |
+
error_msg = "❌ *An error occurred*\n\n💬 *Please type 'main' to go to main menu*"
|
2098 |
+
|
2099 |
+
send_whatsjet_message(from_number, error_msg)
|
2100 |
context_manager.update_context(
|
2101 |
from_number,
|
2102 |
current_state='main_menu',
|
|
|
3754 |
async def handle_intelligent_product_inquiry(from_number: str, query: str, user_context: dict, reply_language: str = 'en'):
|
3755 |
"""Handle product inquiry with OpenAI intelligence and media support"""
|
3756 |
try:
|
3757 |
+
# Clean and normalize the query
|
3758 |
+
clean_query = query.strip().lower()
|
3759 |
+
|
3760 |
+
# Check for common misspellings and variations
|
3761 |
+
misspelling_corrections = {
|
3762 |
+
'aapex': 'apex',
|
3763 |
+
'apex': 'apex biotical',
|
3764 |
+
'ec immune': 'ec-immune',
|
3765 |
+
'ecimmune': 'ec-immune',
|
3766 |
+
'hydro pex': 'hydropex',
|
3767 |
+
'hydropex': 'hydropex',
|
3768 |
+
'respira aid': 'respira aid plus',
|
3769 |
+
'respiraaid': 'respira aid plus',
|
3770 |
+
'hepo sel': 'heposel',
|
3771 |
+
'heposel': 'heposel',
|
3772 |
+
'brom acid': 'bromacid',
|
3773 |
+
'bromacid': 'bromacid',
|
3774 |
+
'hexa tox': 'hexatox',
|
3775 |
+
'hexatox': 'hexatox',
|
3776 |
+
'apma fort': 'apma fort',
|
3777 |
+
'apmafort': 'apma fort',
|
3778 |
+
'para c': 'para c.e',
|
3779 |
+
'para ce': 'para c.e',
|
3780 |
+
'parace': 'para c.e',
|
3781 |
+
'tribiotic': 'tribiotic',
|
3782 |
+
'phyto sal': 'phyto-sal',
|
3783 |
+
'phytosal': 'phyto-sal',
|
3784 |
+
'mycopex': 'mycopex super',
|
3785 |
+
'mycopexsuper': 'mycopex super',
|
3786 |
+
'eflin': 'eflin kt-20',
|
3787 |
+
'eflinkt20': 'eflin kt-20',
|
3788 |
+
'salcozine': 'salcozine st-30',
|
3789 |
+
'salcozinest30': 'salcozine st-30',
|
3790 |
+
'oftilex': 'oftilex ua-10',
|
3791 |
+
'oftilexua10': 'oftilex ua-10',
|
3792 |
+
'biscomin': 'biscomin 10',
|
3793 |
+
'biscomin10': 'biscomin 10',
|
3794 |
+
'apvita': 'apvita plus',
|
3795 |
+
'apvitaplus': 'apvita plus',
|
3796 |
+
'bg aspro': 'b-g aspro-c',
|
3797 |
+
'bgaspro': 'b-g aspro-c',
|
3798 |
+
'liverpex': 'liverpex',
|
3799 |
+
'symodex': 'symodex',
|
3800 |
+
'adek': 'adek gold',
|
3801 |
+
'adekgold': 'adek gold',
|
3802 |
+
'immuno': 'immuno dx',
|
3803 |
+
'immunodx': 'immuno dx',
|
3804 |
+
'mood of action': 'mode of action',
|
3805 |
+
'mode of action': 'mode of action',
|
3806 |
+
'mechanism of action': 'mode of action',
|
3807 |
+
'how does it work': 'mode of action',
|
3808 |
+
'what does it do': 'mode of action',
|
3809 |
+
'how it works': 'mode of action'
|
3810 |
+
}
|
3811 |
+
|
3812 |
+
# Apply misspelling corrections
|
3813 |
+
corrected_query = clean_query
|
3814 |
+
for misspelling, correction in misspelling_corrections.items():
|
3815 |
+
if misspelling in clean_query:
|
3816 |
+
corrected_query = clean_query.replace(misspelling, correction)
|
3817 |
+
logger.info(f"[Query] Applied correction: '{misspelling}' -> '{correction}'")
|
3818 |
+
break
|
3819 |
+
|
3820 |
+
# Check if query is asking about mode of action or mechanism
|
3821 |
+
mode_of_action_keywords = ['mode of action', 'mechanism', 'how does it work', 'what does it do', 'how it works']
|
3822 |
+
is_mode_of_action_query = any(keyword in clean_query for keyword in mode_of_action_keywords)
|
3823 |
+
|
3824 |
+
# First try direct product search with original query
|
3825 |
products = get_veterinary_product_matches(query)
|
3826 |
|
3827 |
+
# If no products found, try with corrected query
|
3828 |
+
if not products and corrected_query != clean_query:
|
3829 |
+
products = get_veterinary_product_matches(corrected_query)
|
3830 |
+
if products:
|
3831 |
+
logger.info(f"[Query] Found products using corrected query: '{corrected_query}'")
|
3832 |
+
|
3833 |
+
# If still no products, try fuzzy matching with product names
|
3834 |
+
if not products:
|
3835 |
+
if products_df is not None and not products_df.empty:
|
3836 |
+
all_product_names = [str(name).lower() for name in products_df['Product Name'].dropna()]
|
3837 |
+
|
3838 |
+
# Use fuzzy matching to find similar product names
|
3839 |
+
for product_name in all_product_names:
|
3840 |
+
similarity = fuzz.ratio(clean_query, product_name)
|
3841 |
+
if similarity >= 80: # 80% similarity threshold
|
3842 |
+
logger.info(f"[Query] Fuzzy match found: '{clean_query}' -> '{product_name}' (similarity: {similarity}%)")
|
3843 |
+
products = get_veterinary_product_matches(product_name)
|
3844 |
+
if products:
|
3845 |
+
break
|
3846 |
+
|
3847 |
if products:
|
3848 |
# Check if this is a broad/category query (multiple products found)
|
3849 |
if len(products) > 1:
|
|
|
3972 |
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
3973 |
)
|
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"
|
3983 |
+
f"📋 *Composition:* {composition}\n\n"
|
3984 |
+
f"💊 *Mechanism:* {indications}\n\n"
|
3985 |
+
f"💬 *For complete product details, select an option below:*\n"
|
3986 |
+
f"1️⃣ Talk to Veterinary Consultant\n"
|
3987 |
+
f"2️⃣ Inquire About Availability\n"
|
3988 |
+
f"3️⃣ Back to Main Menu"
|
3989 |
+
)
|
3990 |
+
|
3991 |
+
send_whatsjet_message(from_number, mode_of_action_response)
|
3992 |
+
else:
|
3993 |
+
# Send product image with caption using the new function
|
3994 |
+
await send_product_image_with_caption(from_number, selected_product, user_context)
|
3995 |
|
3996 |
# Add to conversation history
|
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}")
|
4010 |
+
# Professional error response
|
4011 |
+
if reply_language == 'ur':
|
4012 |
+
error_msg = "❌ *خطا آ گئی ہے*\n\n💬 *براہ کرم 'main' لکھ کر مین مینو پر جائیں*"
|
4013 |
+
else:
|
4014 |
+
error_msg = "❌ *An error occurred*\n\n💬 *Please type 'main' to go to main menu*"
|
4015 |
+
|
4016 |
+
send_whatsjet_message(from_number, error_msg)
|
4017 |
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()))
|
4018 |
|
4019 |
async def handle_contact_request(from_number: str):
|