Update app.py
Browse files
app.py
CHANGED
|
@@ -398,17 +398,23 @@ def match_dish(user_input: str, threshold: int = 70) -> str:
|
|
| 398 |
|
| 399 |
# Enhanced matching function: returns a list of dish names that match the user input.
|
| 400 |
def match_dishes(user_input: str, threshold: int = 70) -> list:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 401 |
matched_dishes = []
|
| 402 |
user_input_lower = user_input.lower()
|
| 403 |
for item in menu_items:
|
| 404 |
dish_name = item["name"]
|
| 405 |
-
#
|
| 406 |
-
|
|
|
|
| 407 |
matched_dishes.append(dish_name)
|
| 408 |
else:
|
| 409 |
score = fuzz.token_sort_ratio(user_input_lower, dish_name.lower())
|
| 410 |
if score >= threshold:
|
| 411 |
matched_dishes.append(dish_name)
|
|
|
|
| 412 |
return list(set(matched_dishes))
|
| 413 |
|
| 414 |
def get_dish_price(dish: str) -> int:
|
|
@@ -716,18 +722,22 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 716 |
if message.lower() in ["yes", "y"]:
|
| 717 |
order_id = f"ORD-{int(time.time())}"
|
| 718 |
state.data["order_id"] = order_id
|
| 719 |
-
|
|
|
|
| 720 |
if "orders" in state.data:
|
| 721 |
total_price = 0
|
| 722 |
for dish, qty in state.data["orders"].items():
|
| 723 |
total_price += get_dish_price(dish) * qty
|
|
|
|
| 724 |
total_price += state.data.get("shipping_cost", 0)
|
| 725 |
dish_summary = ", ".join(state.data["orders"].keys())
|
| 726 |
quantity_total = sum(state.data["orders"].values())
|
| 727 |
else:
|
|
|
|
| 728 |
dish_summary = state.data.get("dish", "")
|
| 729 |
quantity_total = state.data.get("quantity", 1)
|
| 730 |
total_price = (quantity_total * get_dish_price(dish_summary)) + state.data.get("shipping_cost", 0)
|
|
|
|
| 731 |
state.data["price"] = str(total_price)
|
| 732 |
|
| 733 |
async def save_order():
|
|
@@ -746,8 +756,28 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 746 |
asyncio.create_task(save_order())
|
| 747 |
asyncio.create_task(log_order_tracking(order_id, "Order Placed", "Order placed and awaiting payment."))
|
| 748 |
|
| 749 |
-
# Email notification
|
| 750 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 751 |
payment_data = create_paystack_payment_link(email_for_paystack, total_price * 100, order_id)
|
| 752 |
state.reset()
|
| 753 |
if user_id in user_state:
|
|
@@ -771,10 +801,8 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 771 |
"you may opt to pay via bank transfer to Account Number 1433042821, Access Bank, Angelo Food Court 2 "
|
| 772 |
"and send your payment screenshot to this chatbot.")
|
| 773 |
elif message.lower() in ["no", "n"]:
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
del user_state[user_id]
|
| 777 |
-
return "Order canceled. Let me know if you'd like to try again."
|
| 778 |
|
| 779 |
# Final fallback
|
| 780 |
return ""
|
|
|
|
| 398 |
|
| 399 |
# Enhanced matching function: returns a list of dish names that match the user input.
|
| 400 |
def match_dishes(user_input: str, threshold: int = 70) -> list:
|
| 401 |
+
"""
|
| 402 |
+
Returns a list of dish names from the menu that exactly appear as whole words in the user input.
|
| 403 |
+
If not, falls back to fuzzy matching.
|
| 404 |
+
"""
|
| 405 |
matched_dishes = []
|
| 406 |
user_input_lower = user_input.lower()
|
| 407 |
for item in menu_items:
|
| 408 |
dish_name = item["name"]
|
| 409 |
+
# Use regex with word boundaries to match the dish name exactly.
|
| 410 |
+
pattern = r'\b' + re.escape(dish_name.lower()) + r'\b'
|
| 411 |
+
if re.search(pattern, user_input_lower):
|
| 412 |
matched_dishes.append(dish_name)
|
| 413 |
else:
|
| 414 |
score = fuzz.token_sort_ratio(user_input_lower, dish_name.lower())
|
| 415 |
if score >= threshold:
|
| 416 |
matched_dishes.append(dish_name)
|
| 417 |
+
# Remove duplicates if any.
|
| 418 |
return list(set(matched_dishes))
|
| 419 |
|
| 420 |
def get_dish_price(dish: str) -> int:
|
|
|
|
| 722 |
if message.lower() in ["yes", "y"]:
|
| 723 |
order_id = f"ORD-{int(time.time())}"
|
| 724 |
state.data["order_id"] = order_id
|
| 725 |
+
|
| 726 |
+
# Calculate total price based on single-dish or multi-dish order
|
| 727 |
if "orders" in state.data:
|
| 728 |
total_price = 0
|
| 729 |
for dish, qty in state.data["orders"].items():
|
| 730 |
total_price += get_dish_price(dish) * qty
|
| 731 |
+
# Add shipping cost (assumed once for the entire order)
|
| 732 |
total_price += state.data.get("shipping_cost", 0)
|
| 733 |
dish_summary = ", ".join(state.data["orders"].keys())
|
| 734 |
quantity_total = sum(state.data["orders"].values())
|
| 735 |
else:
|
| 736 |
+
# Single-dish order
|
| 737 |
dish_summary = state.data.get("dish", "")
|
| 738 |
quantity_total = state.data.get("quantity", 1)
|
| 739 |
total_price = (quantity_total * get_dish_price(dish_summary)) + state.data.get("shipping_cost", 0)
|
| 740 |
+
|
| 741 |
state.data["price"] = str(total_price)
|
| 742 |
|
| 743 |
async def save_order():
|
|
|
|
| 756 |
asyncio.create_task(save_order())
|
| 757 |
asyncio.create_task(log_order_tracking(order_id, "Order Placed", "Order placed and awaiting payment."))
|
| 758 |
|
| 759 |
+
# Email notification to admin (using your SMTP integration)
|
| 760 |
+
admin_emails = os.getenv("ADMIN_EMAILS", "admin@example.com").split(",")
|
| 761 |
+
email_subject = f"New Order Received: {order_id}"
|
| 762 |
+
email_body = (
|
| 763 |
+
f"New Order Received:\n"
|
| 764 |
+
f"Order ID: {order_id}\n"
|
| 765 |
+
f"Dish(es): {dish_summary}\n"
|
| 766 |
+
f"Quantity: {quantity_total}\n"
|
| 767 |
+
f"Total Price: N{total_price}\n"
|
| 768 |
+
f"Phone: {state.data.get('phone_number', '')}\n"
|
| 769 |
+
f"Delivery Address: {state.data.get('address', 'Not Provided')}\n"
|
| 770 |
+
f"Extras: {state.data.get('extras', 'None')}\n"
|
| 771 |
+
f"Status: Pending Payment"
|
| 772 |
+
)
|
| 773 |
+
email_sent = send_email_notification(admin_emails, email_subject, email_body)
|
| 774 |
+
if email_sent:
|
| 775 |
+
print("Email notification sent successfully.")
|
| 776 |
+
else:
|
| 777 |
+
print("Failed to send email notification.")
|
| 778 |
+
|
| 779 |
+
# Generate Paystack payment link (amount in kobo)
|
| 780 |
+
email_for_paystack = "customer@example.com" # Replace with user's email if available
|
| 781 |
payment_data = create_paystack_payment_link(email_for_paystack, total_price * 100, order_id)
|
| 782 |
state.reset()
|
| 783 |
if user_id in user_state:
|
|
|
|
| 801 |
"you may opt to pay via bank transfer to Account Number 1433042821, Access Bank, Angelo Food Court 2 "
|
| 802 |
"and send your payment screenshot to this chatbot.")
|
| 803 |
elif message.lower() in ["no", "n"]:
|
| 804 |
+
# Instead of immediately canceling, re-prompt for confirmation.
|
| 805 |
+
return "Please confirm your order by typing 'yes' to confirm or 'no' to cancel."
|
|
|
|
|
|
|
| 806 |
|
| 807 |
# Final fallback
|
| 808 |
return ""
|