Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -2318,26 +2318,24 @@ async def process_incoming_message(from_number: str, msg: dict):
|
|
2318 |
send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
|
2319 |
elif current_state == 'all_products_menu':
|
2320 |
# Handle product selection from all products
|
2321 |
-
|
2322 |
-
|
2323 |
-
|
2324 |
-
|
2325 |
-
|
2326 |
-
|
2327 |
-
|
2328 |
-
|
2329 |
-
|
2330 |
-
|
2331 |
-
|
2332 |
-
|
2333 |
-
else:
|
2334 |
-
send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
|
2335 |
else:
|
2336 |
-
send_whatsjet_message(from_number,
|
|
|
2337 |
elif current_state == 'product_inquiry':
|
2338 |
await handle_veterinary_product_followup(message_body, from_number)
|
2339 |
elif current_state == 'intelligent_products_menu':
|
2340 |
-
# Handle product selection from intelligent products menu
|
2341 |
available_products = user_context.get('available_products', [])
|
2342 |
if message_body.isdigit() and 1 <= int(message_body) <= len(available_products):
|
2343 |
selected_product = available_products[int(message_body) - 1]
|
@@ -4445,523 +4443,53 @@ async def test_send_product_image(phone: str, product_name: str = "Bromacid"):
|
|
4445 |
return {"error": str(e)}
|
4446 |
|
4447 |
async def handle_intelligent_product_inquiry(from_number: str, query: str, user_context: dict, reply_language: str = 'en'):
|
4448 |
-
"""Handle product inquiry with OpenAI intelligence and media support"""
|
4449 |
try:
|
4450 |
-
# Check for intelligent product count queries
|
4451 |
-
count_keywords = ['how many', 'count', 'number of', 'total', 'quantity', 'amount']
|
4452 |
-
is_count_query = any(keyword in query.lower() for keyword in count_keywords)
|
4453 |
-
|
4454 |
-
if is_count_query and products_df is not None and not products_df.empty:
|
4455 |
-
# Intelligent count analysis
|
4456 |
-
query_lower = query.lower()
|
4457 |
-
|
4458 |
-
# Check if it's asking for total products
|
4459 |
-
total_indicators = ['total products', 'all products', 'products you have', 'products in total', 'total medicines', 'all medicines']
|
4460 |
-
is_total_query = any(indicator in query_lower for indicator in total_indicators)
|
4461 |
-
|
4462 |
-
if is_total_query:
|
4463 |
-
# Total products count
|
4464 |
-
total_products = len(products_df)
|
4465 |
-
categories = products_df['Category'].dropna().unique()
|
4466 |
-
total_categories = len(categories)
|
4467 |
-
|
4468 |
-
if reply_language == 'ur':
|
4469 |
-
response = (
|
4470 |
-
f"📊 *کل مصنوعات کی تعداد*\n\n"
|
4471 |
-
f"ہمارے پاس کل **{total_products}** ویٹرنری مصنوعات ہیں۔\n\n"
|
4472 |
-
f"📂 *زمرے:* {total_categories}\n"
|
4473 |
-
f"📦 *مصنوعات:* {total_products}\n\n"
|
4474 |
-
"💡 *مثال کے طور پر:*\n"
|
4475 |
-
"• 'سانس کی مصنوعات دکھائیں'\n"
|
4476 |
-
"• 'hydropex کے بارے میں بتائیں'\n"
|
4477 |
-
"• 'main' لکھ کر مین مینو پر جائیں"
|
4478 |
-
)
|
4479 |
-
else:
|
4480 |
-
response = (
|
4481 |
-
f"📊 *Total Product Count*\n\n"
|
4482 |
-
f"We have a total of **{total_products}** veterinary products.\n\n"
|
4483 |
-
f"📂 *Categories:* {total_categories}\n"
|
4484 |
-
f"📦 *Products:* {total_products}\n\n"
|
4485 |
-
"💡 *Examples:*\n"
|
4486 |
-
"• 'Show me respiratory products'\n"
|
4487 |
-
"• 'Tell me about hydropex'\n"
|
4488 |
-
"• Type 'main' to return to main menu"
|
4489 |
-
)
|
4490 |
-
|
4491 |
-
send_whatsjet_message(from_number, response)
|
4492 |
-
return
|
4493 |
-
else:
|
4494 |
-
# Specific category/product type count
|
4495 |
-
# Extract search terms from the query
|
4496 |
-
search_terms = []
|
4497 |
-
|
4498 |
-
# Common veterinary categories and terms
|
4499 |
-
category_mappings = {
|
4500 |
-
'respiratory': ['respiratory', 'breathing', 'lung', 'bronchi', 'respira'],
|
4501 |
-
'liver': ['liver', 'hepatic', 'hepat', 'hepo'],
|
4502 |
-
'antibiotic': ['antibiotic', 'anti-biotic', 'biotic', 'tribiotic'],
|
4503 |
-
'vitamin': ['vitamin', 'vit', 'multivitamin', 'symodex', 'adek'],
|
4504 |
-
'electrolyte': ['electrolyte', 'hydropex', 'rehydration'],
|
4505 |
-
'poultry': ['poultry', 'chicken', 'bird', 'avian'],
|
4506 |
-
'livestock': ['livestock', 'cattle', 'cow', 'buffalo', 'animal'],
|
4507 |
-
'immune': ['immune', 'immunity', 'immuno', 'ec-immune'],
|
4508 |
-
'parasite': ['parasite', 'parasitic', 'para'],
|
4509 |
-
'antifungal': ['antifungal', 'fungal', 'myco'],
|
4510 |
-
'pain': ['pain', 'analgesic', 'painkiller'],
|
4511 |
-
'fever': ['fever', 'pyrexia', 'temperature']
|
4512 |
-
}
|
4513 |
-
|
4514 |
-
# Find matching categories
|
4515 |
-
matched_categories = []
|
4516 |
-
for category, terms in category_mappings.items():
|
4517 |
-
if any(term in query_lower for term in terms):
|
4518 |
-
matched_categories.append(category)
|
4519 |
-
|
4520 |
-
# Search in CSV for matching products
|
4521 |
-
matching_products = []
|
4522 |
-
if matched_categories:
|
4523 |
-
for category in matched_categories:
|
4524 |
-
# Search by category name
|
4525 |
-
category_products = products_df[
|
4526 |
-
products_df['Category'].str.lower().str.contains(category, na=False) |
|
4527 |
-
products_df['Product Name'].str.lower().str.contains(category, na=False) |
|
4528 |
-
products_df['Target Species'].str.lower().str.contains(category, na=False) |
|
4529 |
-
products_df['Mode of Action'].str.lower().str.contains(category, na=False)
|
4530 |
-
]
|
4531 |
-
matching_products.extend(category_products.to_dict('records'))
|
4532 |
-
|
4533 |
-
# Remove duplicates
|
4534 |
-
seen_names = set()
|
4535 |
-
unique_products = []
|
4536 |
-
for product in matching_products:
|
4537 |
-
name = product.get('Product Name', '')
|
4538 |
-
if name not in seen_names:
|
4539 |
-
seen_names.add(name)
|
4540 |
-
unique_products.append(product)
|
4541 |
-
|
4542 |
-
matching_products = unique_products
|
4543 |
-
else:
|
4544 |
-
# If no specific category found, search for any terms in the query
|
4545 |
-
query_words = query_lower.split()
|
4546 |
-
for word in query_words:
|
4547 |
-
if len(word) > 3: # Only search for meaningful words
|
4548 |
-
word_products = products_df[
|
4549 |
-
products_df['Category'].str.lower().str.contains(word, na=False) |
|
4550 |
-
products_df['Product Name'].str.lower().str.contains(word, na=False) |
|
4551 |
-
products_df['Target Species'].str.lower().str.contains(word, na=False) |
|
4552 |
-
products_df['Mode of Action'].str.lower().str.contains(word, na=False)
|
4553 |
-
]
|
4554 |
-
matching_products.extend(word_products.to_dict('records'))
|
4555 |
-
|
4556 |
-
# Remove duplicates
|
4557 |
-
seen_names = set()
|
4558 |
-
unique_products = []
|
4559 |
-
for product in matching_products:
|
4560 |
-
name = product.get('Product Name', '')
|
4561 |
-
if name not in seen_names:
|
4562 |
-
seen_names.add(name)
|
4563 |
-
unique_products.append(product)
|
4564 |
-
|
4565 |
-
matching_products = unique_products
|
4566 |
-
|
4567 |
-
# Generate response based on results
|
4568 |
-
if matching_products:
|
4569 |
-
count = len(matching_products)
|
4570 |
-
|
4571 |
-
# Get category breakdown
|
4572 |
-
categories_found = {}
|
4573 |
-
for product in matching_products:
|
4574 |
-
category = product.get('Category', 'Unknown')
|
4575 |
-
categories_found[category] = categories_found.get(category, 0) + 1
|
4576 |
-
|
4577 |
-
if reply_language == 'ur':
|
4578 |
-
response = (
|
4579 |
-
f"📊 *{query}*\n\n"
|
4580 |
-
f"ہمارے پاس **{count}** مصنوعات ملی ہیں۔\n\n"
|
4581 |
-
)
|
4582 |
-
|
4583 |
-
if len(categories_found) > 1:
|
4584 |
-
response += "📂 *زمرے کے مطابق:*\n"
|
4585 |
-
for category, cat_count in categories_found.items():
|
4586 |
-
response += f"• {category}: {cat_count}\n"
|
4587 |
-
response += "\n"
|
4588 |
-
|
4589 |
-
response += (
|
4590 |
-
"💡 *مثال کے طور پر:*\n"
|
4591 |
-
"• 'سانس کی مصنوعات دکھائیں'\n"
|
4592 |
-
"• 'hydropex کے بارے میں بتائیں'\n"
|
4593 |
-
"• 'main' لکھ کر مین مینو پر جائیں"
|
4594 |
-
)
|
4595 |
-
else:
|
4596 |
-
response = (
|
4597 |
-
f"📊 *{query}*\n\n"
|
4598 |
-
f"We found **{count}** products.\n\n"
|
4599 |
-
)
|
4600 |
-
|
4601 |
-
if len(categories_found) > 1:
|
4602 |
-
response += "📂 *By Category:*\n"
|
4603 |
-
for category, cat_count in categories_found.items():
|
4604 |
-
response += f"• {category}: {cat_count}\n"
|
4605 |
-
response += "\n"
|
4606 |
-
|
4607 |
-
response += (
|
4608 |
-
"💡 *Examples:*\n"
|
4609 |
-
"• 'Show me respiratory products'\n"
|
4610 |
-
"• 'Tell me about hydropex'\n"
|
4611 |
-
"• Type 'main' to return to main menu"
|
4612 |
-
)
|
4613 |
-
|
4614 |
-
send_whatsjet_message(from_number, response)
|
4615 |
-
return
|
4616 |
-
else:
|
4617 |
-
# No matching products found
|
4618 |
-
if reply_language == 'ur':
|
4619 |
-
response = (
|
4620 |
-
f"❌ *{query}*\n\n"
|
4621 |
-
"ہمیں کوئی مصنوعات نہیں ملی۔\n\n"
|
4622 |
-
"💡 *مثال کے طور پر:*\n"
|
4623 |
-
"• 'سانس کی مصنوعات'\n"
|
4624 |
-
"• 'جگر کی مصنوعات'\n"
|
4625 |
-
"• 'main' لکھ کر مین مینو پر جائیں"
|
4626 |
-
)
|
4627 |
-
else:
|
4628 |
-
response = (
|
4629 |
-
f"❌ *{query}*\n\n"
|
4630 |
-
"No products found matching your query.\n\n"
|
4631 |
-
"💡 *Try:*\n"
|
4632 |
-
"• 'respiratory products'\n"
|
4633 |
-
"• 'liver products'\n"
|
4634 |
-
"• Type 'main' to return to main menu"
|
4635 |
-
)
|
4636 |
-
|
4637 |
-
send_whatsjet_message(from_number, response)
|
4638 |
-
return
|
4639 |
-
|
4640 |
-
# Clean and normalize the query
|
4641 |
-
clean_query = query.strip().lower()
|
4642 |
-
|
4643 |
-
# Check for common misspellings and variations
|
4644 |
-
misspelling_corrections = {
|
4645 |
-
'aapex': 'apex',
|
4646 |
-
'apex': 'apex biotical',
|
4647 |
-
'ec immune': 'ec-immune',
|
4648 |
-
'ecimmune': 'ec-immune',
|
4649 |
-
'hydro pex': 'hydropex',
|
4650 |
-
'hydropex': 'hydropex',
|
4651 |
-
'respira aid': 'respira aid plus',
|
4652 |
-
'respiraaid': 'respira aid plus',
|
4653 |
-
'hepo sel': 'heposel',
|
4654 |
-
'heposel': 'heposel',
|
4655 |
-
'brom acid': 'bromacid',
|
4656 |
-
'bromacid': 'bromacid',
|
4657 |
-
'hexa tox': 'hexatox',
|
4658 |
-
'hexatox': 'hexatox',
|
4659 |
-
'apma fort': 'apma fort',
|
4660 |
-
'apmafort': 'apma fort',
|
4661 |
-
'para c': 'para c.e',
|
4662 |
-
'para ce': 'para c.e',
|
4663 |
-
'parace': 'para c.e',
|
4664 |
-
'tribiotic': 'tribiotic',
|
4665 |
-
'phyto sal': 'phyto-sal',
|
4666 |
-
'phytosal': 'phyto-sal',
|
4667 |
-
'mycopex': 'mycopex super',
|
4668 |
-
'mycopexsuper': 'mycopex super',
|
4669 |
-
'eflin': 'eflin kt-20',
|
4670 |
-
'eflinkt20': 'eflin kt-20',
|
4671 |
-
'salcozine': 'salcozine st-30',
|
4672 |
-
'salcozinest30': 'salcozine st-30',
|
4673 |
-
'oftilex': 'oftilex ua-10',
|
4674 |
-
'oftilexua10': 'oftilex ua-10',
|
4675 |
-
'biscomin': 'biscomin 10',
|
4676 |
-
'biscomin10': 'biscomin 10',
|
4677 |
-
'apvita': 'apvita plus',
|
4678 |
-
'apvitaplus': 'apvita plus',
|
4679 |
-
'bg aspro': 'b-g aspro-c',
|
4680 |
-
'bgaspro': 'b-g aspro-c',
|
4681 |
-
'liverpex': 'liverpex',
|
4682 |
-
'symodex': 'symodex',
|
4683 |
-
'adek': 'adek gold',
|
4684 |
-
'adekgold': 'adek gold',
|
4685 |
-
'immuno': 'immuno dx',
|
4686 |
-
'immunodx': 'immuno dx',
|
4687 |
-
'mood of action': 'mode of action',
|
4688 |
-
'mode of action': 'mode of action',
|
4689 |
-
'mechanism of action': 'mode of action',
|
4690 |
-
'how does it work': 'mode of action',
|
4691 |
-
'what does it do': 'mode of action',
|
4692 |
-
'how it works': 'mode of action'
|
4693 |
-
}
|
4694 |
-
|
4695 |
-
# Apply misspelling corrections
|
4696 |
-
corrected_query = clean_query
|
4697 |
-
for misspelling, correction in misspelling_corrections.items():
|
4698 |
-
if misspelling in clean_query:
|
4699 |
-
corrected_query = clean_query.replace(misspelling, correction)
|
4700 |
-
logger.info(f"[Query] Applied correction: '{misspelling}' -> '{correction}'")
|
4701 |
-
break
|
4702 |
-
|
4703 |
-
# Check if query is asking about mode of action or mechanism
|
4704 |
-
mode_of_action_keywords = ['mode of action', 'mechanism', 'how does it work', 'what does it do', 'how it works']
|
4705 |
-
is_mode_of_action_query = any(keyword in clean_query for keyword in mode_of_action_keywords)
|
4706 |
-
|
4707 |
-
# First try direct product search with original query
|
4708 |
products = get_veterinary_product_matches(query)
|
4709 |
-
|
4710 |
-
# If no products found, try with corrected query
|
4711 |
-
if not products and corrected_query != clean_query:
|
4712 |
-
products = get_veterinary_product_matches(corrected_query)
|
4713 |
-
if products:
|
4714 |
-
logger.info(f"[Query] Found products using corrected query: '{corrected_query}'")
|
4715 |
-
|
4716 |
-
# If still no products, try fuzzy matching with product names
|
4717 |
-
if not products:
|
4718 |
-
if products_df is not None and not products_df.empty:
|
4719 |
-
all_product_names = [str(name).lower() for name in products_df['Product Name'].dropna()]
|
4720 |
-
|
4721 |
-
# Use fuzzy matching to find similar product names
|
4722 |
-
for product_name in all_product_names:
|
4723 |
-
similarity = fuzz.ratio(clean_query, product_name)
|
4724 |
-
if similarity >= 80: # 80% similarity threshold
|
4725 |
-
logger.info(f"[Query] Fuzzy match found: '{clean_query}' -> '{product_name}' (similarity: {similarity}%)")
|
4726 |
-
products = get_veterinary_product_matches(product_name)
|
4727 |
-
if products:
|
4728 |
-
break
|
4729 |
-
|
4730 |
if products:
|
4731 |
-
# Check if this is a broad/category query (multiple products found)
|
4732 |
if len(products) > 1:
|
4733 |
-
#
|
4734 |
-
|
4735 |
-
try:
|
4736 |
-
# Create a comprehensive prompt for multiple products
|
4737 |
-
products_info = []
|
4738 |
-
for i, product in enumerate(products, 1):
|
4739 |
-
product_name = product.get('Product Name', 'N/A')
|
4740 |
-
category = product.get('Category', 'N/A')
|
4741 |
-
target_species = product.get('Target Species', 'N/A')
|
4742 |
-
products_info.append(f"{i}. {product_name} - {category} ({target_species})")
|
4743 |
-
|
4744 |
-
products_text = "\n".join(products_info)
|
4745 |
-
|
4746 |
-
prompt = f"""
|
4747 |
-
You are a professional veterinary product assistant for Apex Biotical. The user asked about "{query}" and we found {len(products)} relevant products.
|
4748 |
-
|
4749 |
-
Available Products:
|
4750 |
-
{products_text}
|
4751 |
-
|
4752 |
-
Please provide a CONCISE response:
|
4753 |
-
1. Brief acknowledgment (1 line max)
|
4754 |
-
2. Simple numbered list of products with category only
|
4755 |
-
3. Clear instructions on how to proceed
|
4756 |
-
|
4757 |
-
Keep it SHORT and PRECISE. No marketing language, no detailed explanations, no repetition.
|
4758 |
-
Format: Brief intro + numbered list + instructions only.
|
4759 |
-
"""
|
4760 |
-
|
4761 |
-
response = openai.ChatCompletion.create(
|
4762 |
-
model="gpt-4o",
|
4763 |
-
messages=[{"role": "user", "content": prompt}],
|
4764 |
-
temperature=0.7,
|
4765 |
-
max_tokens=400
|
4766 |
-
)
|
4767 |
-
|
4768 |
-
ai_response = response.choices[0].message['content'].strip()
|
4769 |
-
|
4770 |
-
# Add instructions for selection
|
4771 |
-
selection_instructions = (
|
4772 |
-
f"\n\n💬 *To view detailed information about any product, reply with its number (1-{len(products)})*\n"
|
4773 |
-
"💬 *Type 'main' to return to the main menu*"
|
4774 |
-
)
|
4775 |
-
|
4776 |
-
full_response = ai_response + selection_instructions
|
4777 |
-
|
4778 |
-
# Translate response if needed (ENGLISH/URDU ONLY)
|
4779 |
-
if reply_language == 'ur':
|
4780 |
-
try:
|
4781 |
-
# Only translate from English to Urdu - no other languages
|
4782 |
-
translated_response = GoogleTranslator(source='en', target='ur').translate(full_response)
|
4783 |
-
send_whatsjet_message(from_number, translated_response)
|
4784 |
-
except Exception as e:
|
4785 |
-
logger.error(f"[AI] Translation error: {e}")
|
4786 |
-
send_whatsjet_message(from_number, full_response)
|
4787 |
-
else:
|
4788 |
-
send_whatsjet_message(from_number, full_response)
|
4789 |
-
|
4790 |
-
# Store the product list in context for selection handling
|
4791 |
-
context_manager.update_context(
|
4792 |
-
from_number,
|
4793 |
-
current_state='intelligent_products_menu',
|
4794 |
-
current_menu='intelligent_products_menu',
|
4795 |
-
current_menu_options=[f"Product {i+1}" for i in range(len(products))],
|
4796 |
-
available_products=products,
|
4797 |
-
last_query=query
|
4798 |
-
)
|
4799 |
-
|
4800 |
-
# Add to conversation history
|
4801 |
-
context_manager.add_to_history(from_number, query, full_response)
|
4802 |
-
return
|
4803 |
-
|
4804 |
-
except Exception as e:
|
4805 |
-
logger.error(f"[AI] Error generating product summary: {e}")
|
4806 |
-
# Fall back to simple listing if AI fails
|
4807 |
-
pass
|
4808 |
-
|
4809 |
-
# Fallback: Simple listing without AI
|
4810 |
-
message = f"🔍 *Found {len(products)} products matching '{query}':*\n\n"
|
4811 |
-
|
4812 |
for i, product in enumerate(products, 1):
|
4813 |
-
product_name = product.get('Product Name', '
|
4814 |
-
category = product.get('Category', '
|
4815 |
-
|
4816 |
-
message += f"{
|
4817 |
-
|
4818 |
-
|
4819 |
-
|
4820 |
-
|
4821 |
-
|
4822 |
-
)
|
4823 |
-
|
4824 |
-
|
4825 |
-
|
4826 |
-
try:
|
4827 |
-
# Only translate from English to Urdu - no other languages
|
4828 |
-
translated_message = GoogleTranslator(source='en', target='ur').translate(message)
|
4829 |
-
send_whatsjet_message(from_number, translated_message)
|
4830 |
-
except Exception as e:
|
4831 |
-
logger.error(f"[AI] Translation error: {e}")
|
4832 |
-
send_whatsjet_message(from_number, message)
|
4833 |
-
else:
|
4834 |
-
send_whatsjet_message(from_number, message)
|
4835 |
-
|
4836 |
-
# Store the product list in context for selection handling
|
4837 |
context_manager.update_context(
|
4838 |
-
from_number,
|
4839 |
current_state='intelligent_products_menu',
|
4840 |
current_menu='intelligent_products_menu',
|
4841 |
-
current_menu_options=[
|
4842 |
-
available_products=products
|
4843 |
-
last_query=query
|
4844 |
)
|
4845 |
-
|
4846 |
-
# Add to conversation history
|
4847 |
-
context_manager.add_to_history(from_number, query, message)
|
4848 |
-
|
4849 |
else:
|
4850 |
-
# Single product found - show
|
4851 |
selected_product = products[0]
|
4852 |
context_manager.update_context(
|
4853 |
-
from_number,
|
4854 |
-
current_product=selected_product,
|
4855 |
current_state='product_inquiry',
|
4856 |
current_menu='product_inquiry',
|
4857 |
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
4858 |
)
|
4859 |
-
|
4860 |
-
|
4861 |
-
if is_mode_of_action_query:
|
4862 |
-
product_name = clean_special_characters(selected_product.get('Product Name', 'Unknown'))
|
4863 |
-
composition = clean_special_characters(selected_product.get('Composition', 'Not specified'))
|
4864 |
-
indications = clean_special_characters(selected_product.get('Indications', 'Not specified'))
|
4865 |
-
|
4866 |
-
mode_of_action_response = (
|
4867 |
-
f"🧪 *{product_name} - Mode of Action*\n\n"
|
4868 |
-
f"📋 *Composition:* {composition}\n\n"
|
4869 |
-
f"💊 *Mechanism:* {indications}\n\n"
|
4870 |
-
f"💬 *For complete product details, select an option below:*\n"
|
4871 |
-
f"1️⃣ Talk to Veterinary Consultant\n"
|
4872 |
-
f"2️⃣ Inquire About Availability\n"
|
4873 |
-
f"3️⃣ Back to Main Menu"
|
4874 |
-
)
|
4875 |
-
|
4876 |
-
send_whatsjet_message(from_number, mode_of_action_response)
|
4877 |
-
else:
|
4878 |
-
# Send product image with caption using the new function
|
4879 |
-
await send_product_image_with_caption(from_number, selected_product, user_context)
|
4880 |
-
|
4881 |
-
# Add to conversation history
|
4882 |
-
context_manager.add_to_history(from_number, query, f"Product inquiry for {selected_product.get('Product Name', 'Unknown')}")
|
4883 |
-
|
4884 |
else:
|
4885 |
-
# No products found
|
4886 |
-
|
4887 |
-
# Check if it might be about a product but needs clarification
|
4888 |
-
if 'apex' in clean_query:
|
4889 |
-
# Direct response about Apex Biotical
|
4890 |
-
if reply_language == 'ur':
|
4891 |
-
message = (
|
4892 |
-
"🏥 *Apex Biotical Solutions*\n\n"
|
4893 |
-
"ہم ایک پیشہ ور ویٹرنری فارماسیوٹیکل کمپنی ہیں جو مندرجہ ذیل میں مہارت رکھتے ہیں:\n\n"
|
4894 |
-
"📦 *ہماری مصنوعات:*\n"
|
4895 |
-
"• سانس کی مدد (Respira Aid Plus, Bromacid)\n"
|
4896 |
-
"• جگر کی صحت (Heposel, Liverpex)\n"
|
4897 |
-
"• مدافعتی نظام (EC-Immune)\n"
|
4898 |
-
"• اینٹی بائیوٹکس (Tribiotic, Para C.E)\n"
|
4899 |
-
"• وٹامنز اور سپلیمنٹس (Symodex, Adek Gold)\n\n"
|
4900 |
-
"💬 *مصنوعات دیکھنے کے لیے:*\n"
|
4901 |
-
"• 'main' لکھ کر مین مینو پر جائیں"
|
4902 |
-
)
|
4903 |
-
else:
|
4904 |
-
message = (
|
4905 |
-
"🏥 *Apex Biotical Solutions*\n\n"
|
4906 |
-
"We are a leading veterinary pharmaceutical company specializing in:\n\n"
|
4907 |
-
"📦 *Our Products:*\n"
|
4908 |
-
"• Respiratory support (Respira Aid Plus, Bromacid)\n"
|
4909 |
-
"• Liver health (Heposel, Liverpex)\n"
|
4910 |
-
"• Immune system (EC-Immune)\n"
|
4911 |
-
"• Antibiotics (Tribiotic, Para C.E)\n"
|
4912 |
-
"• Vitamins & supplements (Symodex, Adek Gold)\n\n"
|
4913 |
-
"🌍 *Our Focus:*\n"
|
4914 |
-
"• Professional veterinary solutions\n"
|
4915 |
-
"• Quality pharmaceutical products\n"
|
4916 |
-
"• Comprehensive animal healthcare\n\n"
|
4917 |
-
"💬 *To explore our products:*\n"
|
4918 |
-
"• Type 'main' to see the main menu\n"
|
4919 |
-
"• Type a product name (e.g., 'hydropex', 'respira aid plus')"
|
4920 |
-
)
|
4921 |
-
send_whatsjet_message(from_number, message)
|
4922 |
-
context_manager.add_to_history(from_number, query, message)
|
4923 |
-
return
|
4924 |
-
elif any(product_hint in clean_query for product_hint in ['immune', 'hydro', 'hepo', 'brom', 'trib', 'symo']):
|
4925 |
-
# Use OpenAI for intelligent response about veterinary topics
|
4926 |
-
if OPENAI_API_KEY:
|
4927 |
-
await handle_ai_chat_mode(from_number, query, reply_language)
|
4928 |
-
else:
|
4929 |
-
# Fallback to generic response
|
4930 |
-
if reply_language == 'ur':
|
4931 |
-
message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
|
4932 |
-
else:
|
4933 |
-
message = "❌ *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
|
4934 |
-
send_whatsjet_message(from_number, message)
|
4935 |
-
else:
|
4936 |
-
# Use OpenAI for general veterinary questions
|
4937 |
-
if OPENAI_API_KEY:
|
4938 |
-
await handle_ai_chat_mode(from_number, query, reply_language)
|
4939 |
-
else:
|
4940 |
-
# Fallback to generic response
|
4941 |
-
if reply_language == 'ur':
|
4942 |
-
message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
|
4943 |
-
else:
|
4944 |
-
message = "❌ *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
|
4945 |
-
send_whatsjet_message(from_number, message)
|
4946 |
-
else:
|
4947 |
-
# Generic, professional "not found" response
|
4948 |
-
if reply_language == 'ur':
|
4949 |
-
message = "❌ *سوال درست نہیں ہے*\n\n💬 *براہ کرم اپنا سوال درست کریں یا 'main' لکھ کر مین مینو پر جائیں*"
|
4950 |
-
else:
|
4951 |
-
message = "❌ *Please correct your question*\n\n💬 *Type 'main' to go to main menu*"
|
4952 |
-
|
4953 |
-
send_whatsjet_message(from_number, message)
|
4954 |
-
|
4955 |
except Exception as e:
|
4956 |
-
logger.error(f"Error in
|
4957 |
-
|
4958 |
-
if reply_language == 'ur':
|
4959 |
-
error_msg = "❌ *خطا آ گئی ہے*\n\n💬 *براہ کرم 'main' لکھ کر مین مینو پر جائیں*"
|
4960 |
-
else:
|
4961 |
-
error_msg = "❌ *An error occurred*\n\n💬 *Please type 'main' to go to main menu*"
|
4962 |
-
|
4963 |
-
send_whatsjet_message(from_number, error_msg)
|
4964 |
-
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()))
|
4965 |
|
4966 |
async def handle_contact_request(from_number: str):
|
4967 |
"""Handle contact request"""
|
|
|
2318 |
send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
|
2319 |
elif current_state == 'all_products_menu':
|
2320 |
# Handle product selection from all products
|
2321 |
+
available_products = user_context.get('available_products', [])
|
2322 |
+
if message_body.isdigit() and 1 <= int(message_body) <= len(available_products):
|
2323 |
+
selected_product = available_products[int(message_body) - 1]
|
2324 |
+
context_manager.update_context(
|
2325 |
+
from_number,
|
2326 |
+
current_product=selected_product,
|
2327 |
+
current_state='product_inquiry',
|
2328 |
+
current_menu='product_inquiry',
|
2329 |
+
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
2330 |
+
)
|
2331 |
+
await send_product_image_with_caption(from_number, selected_product, user_context)
|
2332 |
+
return
|
|
|
|
|
2333 |
else:
|
2334 |
+
send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
|
2335 |
+
return
|
2336 |
elif current_state == 'product_inquiry':
|
2337 |
await handle_veterinary_product_followup(message_body, from_number)
|
2338 |
elif current_state == 'intelligent_products_menu':
|
|
|
2339 |
available_products = user_context.get('available_products', [])
|
2340 |
if message_body.isdigit() and 1 <= int(message_body) <= len(available_products):
|
2341 |
selected_product = available_products[int(message_body) - 1]
|
|
|
4443 |
return {"error": str(e)}
|
4444 |
|
4445 |
async def handle_intelligent_product_inquiry(from_number: str, query: str, user_context: dict, reply_language: str = 'en'):
|
4446 |
+
"""Handle product inquiry with OpenAI intelligence and media support, matching WhatsApp screenshot logic"""
|
4447 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4448 |
products = get_veterinary_product_matches(query)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4449 |
if products:
|
|
|
4450 |
if len(products) > 1:
|
4451 |
+
# Numbered list with short descriptions
|
4452 |
+
message = f"Certainly, here are the relevant products for your query:\n\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4453 |
for i, product in enumerate(products, 1):
|
4454 |
+
product_name = product.get('Product Name', 'Unknown')
|
4455 |
+
category = product.get('Category', '')
|
4456 |
+
short_desc = product.get('Type', '') or product.get('Indications', '')
|
4457 |
+
message += f"{i}. {product_name}"
|
4458 |
+
if category:
|
4459 |
+
message += f" - {category}"
|
4460 |
+
if short_desc:
|
4461 |
+
message += f" / {short_desc}"
|
4462 |
+
message += "\n"
|
4463 |
+
message += (f"\nTo view detailed information about any product, reply with its number (1-{len(products)})\n"
|
4464 |
+
"Type 'main' to return to the main menu")
|
4465 |
+
send_whatsjet_message(from_number, message)
|
4466 |
+
# Store product list in context for selection
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4467 |
context_manager.update_context(
|
4468 |
+
from_number,
|
4469 |
current_state='intelligent_products_menu',
|
4470 |
current_menu='intelligent_products_menu',
|
4471 |
+
current_menu_options=[str(i) for i in range(1, len(products)+1)],
|
4472 |
+
available_products=products
|
|
|
4473 |
)
|
4474 |
+
return
|
|
|
|
|
|
|
4475 |
else:
|
4476 |
+
# Single product found - show details
|
4477 |
selected_product = products[0]
|
4478 |
context_manager.update_context(
|
4479 |
+
from_number,
|
4480 |
+
current_product=selected_product,
|
4481 |
current_state='product_inquiry',
|
4482 |
current_menu='product_inquiry',
|
4483 |
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
4484 |
)
|
4485 |
+
await send_product_image_with_caption(from_number, selected_product, user_context)
|
4486 |
+
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4487 |
else:
|
4488 |
+
# No products found
|
4489 |
+
send_whatsjet_message(from_number, "❌ No products found matching your query.\nType 'main' to return to the main menu.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4490 |
except Exception as e:
|
4491 |
+
logger.error(f"Error in handle_intelligent_product_inquiry: {e}")
|
4492 |
+
send_whatsjet_message(from_number, "❌ Error processing your request. Type 'main' to return to the main menu.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4493 |
|
4494 |
async def handle_contact_request(from_number: str):
|
4495 |
"""Handle contact request"""
|