Fred808 commited on
Commit
bd461ef
·
verified ·
1 Parent(s): b355ccd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -95
app.py CHANGED
@@ -385,109 +385,149 @@ def match_dishes(user_input: str, threshold: int = 70) -> list:
385
  return list(set(matched_dishes))
386
 
387
  async def process_order_flow(user_id: str, message: str) -> str:
388
- state = user_state.get(user_id)
389
- if state and state.is_expired():
390
- state.reset()
391
- del user_state[user_id]
392
- state = None
393
-
394
- if message.lower() in ["order", "menu"]:
395
- state = ConversationState()
396
- state.flow = "order"
397
- state.step = 1
398
- state.update_last_active()
399
- user_state[user_id] = state
400
- if message.lower() == "order":
401
- return "Sure! What dish would you like to order?"
402
- return ""
403
-
404
- if not state and "order" in message.lower():
405
- state = ConversationState()
406
- state.flow = "order"
407
- state.step = 1
408
- state.update_last_active()
409
- user_state[user_id] = state
410
- return "Sure! What dish would you like to order?"
411
-
412
- # Use fuzzy matching to detect a dish even with typos
413
- if not state or state.flow != "order":
414
- found_dish = match_dish(message)
415
- if found_dish:
 
416
  state = ConversationState()
417
  state.flow = "order"
418
- state.data["dish"] = found_dish
419
  state.update_last_active()
420
  user_state[user_id] = state
421
- numbers = re.findall(r'\d+', message)
422
- if numbers:
423
- quantity = int(numbers[0])
424
- if quantity <= 0:
425
- return "Please enter a valid quantity (e.g., 1, 2, 3)."
426
- state.data["quantity"] = quantity
427
- state.step = 3
428
- phone_pattern = r'(\+?\d{10,15})'
429
- phone_match = re.search(phone_pattern, message)
430
- address = None
431
- if phone_match:
432
- phone_number = phone_match.group(1)
433
- address_start = phone_match.end()
434
- address = message[address_start:].strip()
435
- address = re.sub(r'^[,\s]+|[,\s]+$', '', address)
436
- if phone_match and address:
437
- state.data["phone_number"] = phone_number
438
- state.data["address"] = address
439
- asyncio.create_task(update_user_profile(user_id, phone_number, address))
440
- shipping_cost = calculate_shipping_cost(address)
441
- state.data["shipping_cost"] = shipping_cost
442
- state.step = 5
443
- return (f"Thanks! Your phone number is recorded as: {phone_number}.\n"
444
- f"Your delivery address is: {address}.\n"
445
- f"Your delivery cost is N{shipping_cost}. Would you like extras (yes/no)?")
446
- elif phone_match:
447
- state.data["phone_number"] = phone_match.group(1)
448
- asyncio.create_task(update_user_profile(user_id, phone_number))
449
- return "Thank you. Please provide your delivery address."
450
- else:
451
- return ("Please provide both your phone number and delivery address. "
452
- "For example: '09162409591, 1, Iyana Isashi, Isashi, Ojo, Lagos'.")
453
- else:
454
- state.step = 2
455
- return f"You selected {found_dish}. How many servings would you like?"
456
-
457
- # If state exists and we're already in order flow:
458
- if state and state.flow == "order":
459
- state.update_last_active()
460
- if state.step == 1:
461
- # Use fuzzy matching on the message in case of typos.
462
- found_dish = match_dish(message)
463
- numbers = re.findall(r'\d+', message)
464
- if found_dish:
465
- state.data["dish"] = found_dish
466
- if numbers:
467
- quantity = int(numbers[0])
468
- if quantity <= 0:
469
- return "Please enter a valid quantity (e.g., 1, 2, 3)."
470
- state.data["quantity"] = quantity
471
- state.step = 3
472
- return (f"You selected {found_dish} with {quantity} serving(s). "
473
- "Please provide your phone number and delivery address.")
474
  else:
475
- state.step = 2
476
- return f"You selected {found_dish}. How many servings would you like?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  else:
478
  return "I couldn't identify the dish. Please type the dish name from our menu."
479
 
480
- if state.step == 2:
481
- numbers = re.findall(r'\d+', message)
482
- if not numbers:
483
- return "Please enter a valid number for the quantity (e.g., 1, 2, 3)."
484
- quantity = int(numbers[0])
485
- if quantity <= 0:
486
- return "Please enter a valid quantity (e.g., 1, 2, 3)."
487
- state.data["quantity"] = quantity
488
- state.step = 3
489
- return f"Got it. {quantity} serving(s) of {state.data.get('dish')}. Please provide your phone number and delivery address."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
 
 
491
  if state.step == 3:
492
  phone_pattern = r'(\+?\d{10,15})'
493
  phone_match = re.search(phone_pattern, message)
@@ -509,7 +549,7 @@ async def process_order_flow(user_id: str, message: str) -> str:
509
  f"Your delivery cost is N{shipping_cost}. Would you like extras (yes/no)?")
510
  elif phone_match:
511
  state.data["phone_number"] = phone_match.group(1)
512
- asyncio.create_task(update_user_profile(user_id, phone_number))
513
  return "Thank you. Please provide your delivery address."
514
  else:
515
  return ("Please provide both your phone number and delivery address. "
 
385
  return list(set(matched_dishes))
386
 
387
  async def process_order_flow(user_id: str, message: str) -> str:
388
+ state = user_state.get(user_id)
389
+ if state and state.is_expired():
390
+ state.reset()
391
+ del user_state[user_id]
392
+ state = None
393
+
394
+ # --- Step 1: If we're already expecting quantity details (multiple dish order) ---
395
+ if state and state.flow == "order" and state.step == 2:
396
+ # Expecting input like "2 for Jollof Rice and 3 for Fried Rice"
397
+ pairs = re.findall(r'(\d+)\s*for\s*([a-zA-Z\s]+)', message, flags=re.IGNORECASE)
398
+ if pairs:
399
+ order_quantities = {}
400
+ candidate_dishes = state.data.get("dishes") # This is set if user said "both"
401
+ if not candidate_dishes:
402
+ candidate_dishes = [state.data.get("dish")]
403
+ for quantity, dish_text in pairs:
404
+ dish_text = dish_text.strip().lower()
405
+ for candidate in candidate_dishes:
406
+ if candidate.lower() in dish_text or dish_text in candidate.lower():
407
+ order_quantities[candidate] = int(quantity)
408
+ if order_quantities:
409
+ state.data["orders"] = order_quantities
410
+ state.step = 3 # Proceed to collecting contact details
411
+ order_summary = "\n".join([f"{q} serving(s) of {d}" for d, q in order_quantities.items()])
412
+ return f"Got it. You have ordered:\n{order_summary}\nPlease provide your phone number and delivery address."
413
+ return "I'm sorry, I didn't understand the quantity details. Please specify like '2 for Jollof Rice and 3 for Fried Rice'."
414
+
415
+ # --- Step 2: Trigger initial order flow ---
416
+ if message.lower() in ["order", "menu"]:
417
  state = ConversationState()
418
  state.flow = "order"
419
+ state.step = 1
420
  state.update_last_active()
421
  user_state[user_id] = state
422
+ if message.lower() == "order":
423
+ return "Sure! What dish would you like to order?"
424
+ return ""
425
+
426
+ if not state and "order" in message.lower():
427
+ state = ConversationState()
428
+ state.flow = "order"
429
+ state.step = 1
430
+ state.update_last_active()
431
+ user_state[user_id] = state
432
+ return "Sure! What dish would you like to order?"
433
+
434
+ # --- Step 3: Identify dish(es) if not already in order flow ---
435
+ # This branch handles when the bot hasn't yet stored a dish.
436
+ if not state or state.flow != "order":
437
+ matched_dishes = match_dishes(message)
438
+ if matched_dishes:
439
+ if len(matched_dishes) > 1:
440
+ # Multiple candidate dishes found.
441
+ state = ConversationState()
442
+ state.flow = "order"
443
+ state.update_last_active()
444
+ state.data["candidate_dishes"] = matched_dishes
445
+ user_state[user_id] = state
446
+ dish_options = ", ".join(matched_dishes)
447
+ return (f"We found multiple dishes in your request: {dish_options}. "
448
+ "Please specify which one you'd like to order or type 'both' if you'd like all.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  else:
450
+ # Single dish identified.
451
+ found_dish = matched_dishes[0]
452
+ state = ConversationState()
453
+ state.flow = "order"
454
+ state.data["dish"] = found_dish
455
+ state.update_last_active()
456
+ user_state[user_id] = state
457
+ # Check if quantity is provided (e.g., "Jollof Rice of 2 portions")
458
+ numbers = re.findall(r'\d+', message)
459
+ if numbers:
460
+ quantity = int(numbers[0])
461
+ if quantity <= 0:
462
+ return "Please enter a valid quantity (e.g., 1, 2, 3)."
463
+ state.data["quantity"] = quantity
464
+ state.step = 3
465
+ # Proceed to extract phone/address below.
466
+ phone_pattern = r'(\+?\d{10,15})'
467
+ phone_match = re.search(phone_pattern, message)
468
+ address = None
469
+ if phone_match:
470
+ phone_number = phone_match.group(1)
471
+ address_start = phone_match.end()
472
+ address = message[address_start:].strip()
473
+ address = re.sub(r'^[,\s]+|[,\s]+$', '', address)
474
+ if phone_match and address:
475
+ state.data["phone_number"] = phone_number
476
+ state.data["address"] = address
477
+ asyncio.create_task(update_user_profile(user_id, phone_number, address))
478
+ shipping_cost = calculate_shipping_cost(address)
479
+ state.data["shipping_cost"] = shipping_cost
480
+ state.step = 5
481
+ return (f"Thanks! Your phone number is recorded as: {phone_number}.\n"
482
+ f"Your delivery address is: {address}.\n"
483
+ f"Your delivery cost is N{shipping_cost}. Would you like extras (yes/no)?")
484
+ elif phone_match:
485
+ state.data["phone_number"] = phone_match.group(1)
486
+ asyncio.create_task(update_user_profile(user_id, phone_match.group(1)))
487
+ return "Thank you. Please provide your delivery address."
488
+ else:
489
+ return (f"You selected {found_dish} with {quantity} serving(s). "
490
+ "Please provide both your phone number and delivery address. "
491
+ "For example: '09162409591, 1, Iyana Isashi, Isashi, Ojo, Lagos'.")
492
+ else:
493
+ state.step = 2
494
+ return f"You selected {found_dish}. How many servings would you like?"
495
  else:
496
  return "I couldn't identify the dish. Please type the dish name from our menu."
497
 
498
+ # --- Step 4: Handle clarification if candidate dishes exist (multiple matches) ---
499
+ if state and state.flow == "order" and "candidate_dishes" in state.data:
500
+ if message.strip().lower() in ["both", "all"]:
501
+ # User chooses to order all candidate dishes.
502
+ state.data["dishes"] = state.data["candidate_dishes"]
503
+ del state.data["candidate_dishes"]
504
+ state.step = 2 # Now expect quantity details for each dish.
505
+ dishes_str = ", ".join(state.data["dishes"])
506
+ return f"You have selected: {dishes_str}. How many servings of each would you like? " \
507
+ "(For example, '2 for Jollof Rice and 3 for Fried Rice')"
508
+ else:
509
+ # Check if the message specifies one of the candidate dishes.
510
+ for dish in state.data["candidate_dishes"]:
511
+ if dish.lower() in message.lower():
512
+ state.data["dish"] = dish
513
+ del state.data["candidate_dishes"]
514
+ numbers = re.findall(r'\d+', message)
515
+ if numbers:
516
+ quantity = int(numbers[0])
517
+ if quantity <= 0:
518
+ return "Please enter a valid quantity (e.g., 1, 2, 3)."
519
+ state.data["quantity"] = quantity
520
+ state.step = 3
521
+ return (f"You selected {dish} with {quantity} serving(s). "
522
+ "Please provide your phone number and delivery address.")
523
+ else:
524
+ state.step = 2
525
+ return f"You selected {dish}. How many servings would you like?"
526
+ dish_options = ", ".join(state.data["candidate_dishes"])
527
+ return f"Please specify which one you'd like to order from: {dish_options} " \
528
+ "(or type 'both' if you'd like to order all)."
529
 
530
+ # --- Step 5: Contact details extraction (for single-dish orders) ---
531
  if state.step == 3:
532
  phone_pattern = r'(\+?\d{10,15})'
533
  phone_match = re.search(phone_pattern, message)
 
549
  f"Your delivery cost is N{shipping_cost}. Would you like extras (yes/no)?")
550
  elif phone_match:
551
  state.data["phone_number"] = phone_match.group(1)
552
+ asyncio.create_task(update_user_profile(user_id, phone_match.group(1)))
553
  return "Thank you. Please provide your delivery address."
554
  else:
555
  return ("Please provide both your phone number and delivery address. "