Fred808 commited on
Commit
52592c8
·
verified ·
1 Parent(s): 1efc26c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -138
app.py CHANGED
@@ -385,147 +385,129 @@ 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
- # --- 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:
 
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
+ # --- Handle quantity details if we're at step 2 ---
395
+ if state and state.flow == "order" and state.step == 2:
396
+ # If the user selected multiple dishes ("both"), we expect "2 for Jollof Rice and 3 for Fried Rice".
397
+ if "dishes" in state.data and len(state.data["dishes"]) > 1:
398
+ # Parse pairs like "(\d+) for ([a-zA-Z\s]+)"
399
  pairs = re.findall(r'(\d+)\s*for\s*([a-zA-Z\s]+)', message, flags=re.IGNORECASE)
400
+ if not pairs:
401
+ return ("I'm sorry, I didn't understand the quantity details. "
402
+ "Please specify like '2 for Jollof Rice and 3 for Fried Rice'.")
403
+ order_quantities = {}
404
+ for quantity, dish_text in pairs:
405
+ dish_text = dish_text.strip().lower()
406
+ for candidate in state.data["dishes"]:
407
+ if candidate.lower() in dish_text or dish_text in candidate.lower():
408
+ order_quantities[candidate] = int(quantity)
409
+ if order_quantities:
410
+ state.data["orders"] = order_quantities
411
+ state.step = 3
412
+ summary = "\n".join([f"{q} serving(s) of {d}" for d, q in order_quantities.items()])
413
+ return (f"Got it. You have ordered:\n{summary}\n"
414
+ "Please provide your phone number and delivery address.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  else:
416
+ return ("I'm sorry, I couldn't match those dishes. "
417
+ "Please try something like '2 for Jollof Rice and 3 for Fried Rice'.")
418
+ else:
419
+ # Single-dish scenario. For example: "2 portions"
420
+ # Just look for a single number in the user message.
421
+ numbers = re.findall(r'\d+', message)
422
+ if not numbers:
423
+ return "Please enter a valid number for the quantity (e.g., 1, 2, 3)."
424
+ quantity = int(numbers[0])
425
+ if quantity <= 0:
426
+ return "Please enter a valid quantity (e.g., 1, 2, 3)."
427
+ state.data["quantity"] = quantity
428
+ state.step = 3
429
+ dish = state.data.get("dish", "")
430
+ return (f"Got it. {quantity} serving(s) of {dish}. "
431
+ "Please provide your phone number and delivery address.")
432
+
433
+ # --- Trigger initial order flow when user types "order" or "menu" ---
434
+ if message.lower() in ["order", "menu"]:
435
+ state = ConversationState()
436
+ state.flow = "order"
437
+ state.step = 1
438
+ state.update_last_active()
439
+ user_state[user_id] = state
440
+ if message.lower() == "order":
441
+ return "Sure! What dish would you like to order?"
442
+ return ""
443
+
444
+ if not state and "order" in message.lower():
445
+ state = ConversationState()
446
+ state.flow = "order"
447
+ state.step = 1
448
+ state.update_last_active()
449
+ user_state[user_id] = state
450
+ return "Sure! What dish would you like to order?"
451
+
452
+ # --- Identify dish(es) if not already in order flow ---
453
+ if not state or state.flow != "order":
454
+ matched_dishes = match_dishes(message)
455
+ if matched_dishes:
456
+ if len(matched_dishes) > 1:
457
+ # Multiple dishes found
458
+ state = ConversationState()
459
+ state.flow = "order"
460
+ state.update_last_active()
461
+ state.data["candidate_dishes"] = matched_dishes
462
+ user_state[user_id] = state
463
+ dish_options = ", ".join(matched_dishes)
464
+ return (f"We found multiple dishes in your request: {dish_options}. "
465
+ "Please specify which one you'd like to order or type 'both' if you'd like all.")
466
  else:
467
+ # Single dish found
468
+ found_dish = matched_dishes[0]
469
+ state = ConversationState()
470
+ state.flow = "order"
471
+ state.data["dish"] = found_dish
472
+ state.update_last_active()
473
+ user_state[user_id] = state
474
+ # Attempt to extract a quantity if present
475
+ numbers = re.findall(r'\d+', message)
476
+ if numbers:
477
+ quantity = int(numbers[0])
478
+ if quantity <= 0:
479
+ return "Please enter a valid quantity (e.g., 1, 2, 3)."
480
+ state.data["quantity"] = quantity
481
+ state.step = 3
482
+ return (f"You selected {found_dish} with {quantity} serving(s). "
483
+ "Please provide your phone number and delivery address.")
484
+ else:
485
+ state.step = 2
486
+ return f"You selected {found_dish}. How many servings would you like?"
487
+ else:
488
+ return "I couldn't identify the dish. Please type the dish name from our menu."
489
+
490
+ # --- Clarification for multiple dishes ---
491
+ if state and state.flow == "order" and "candidate_dishes" in state.data:
492
+ # If user typed "both", they want all candidate dishes
493
+ if message.strip().lower() in ["both", "all"]:
494
+ state.data["dishes"] = state.data["candidate_dishes"]
495
+ del state.data["candidate_dishes"]
496
+ state.step = 2
497
+ dishes_str = ", ".join(state.data["dishes"])
498
+ return (f"You have selected: {dishes_str}. How many servings of each would you like? "
499
+ "(For example, '2 for Jollof Rice and 3 for Fried Rice')")
500
+ else:
501
+ # Check if user specified a single dish out of the candidates
502
+ for dish in state.data["candidate_dishes"]:
503
+ if dish.lower() in message.lower():
504
+ state.data["dish"] = dish
505
+ del state.data["candidate_dishes"]
506
+ state.step = 2
507
+ return f"You selected {dish}. How many servings would you like?"
508
+ dish_options = ", ".join(state.data["candidate_dishes"])
509
+ return (f"Please specify which one you'd like to order from: {dish_options} "
510
+ "(or type 'both' if you'd like to order all).")
511
 
512
  # --- Step 5: Contact details extraction (for single-dish orders) ---
513
  if state.step == 3: