From 1b7c273e55c6ad567d77654073a055e729f3dd9f Mon Sep 17 00:00:00 2001 From: Steve Androulakis Date: Sat, 31 May 2025 01:07:08 -0700 Subject: [PATCH] food ordering for stevea video --- tools/__init__.py | 16 ++++ tools/data/food_ordering_data.json | 122 ++++++++++++++++++++++++++++ tools/food/add_to_cart.py | 63 ++++++++++++++ tools/food/check_order_status.py | 28 +++++++ tools/food/get_menu.py | 23 ++++++ tools/food/get_menu_item_details.py | 23 ++++++ tools/food/place_order.py | 57 +++++++++++++ tools/goal_registry.py | 45 ++++++++++ tools/tool_registry.py | 86 ++++++++++++++++++++ 9 files changed, 463 insertions(+) create mode 100644 tools/data/food_ordering_data.json create mode 100644 tools/food/add_to_cart.py create mode 100644 tools/food/check_order_status.py create mode 100644 tools/food/get_menu.py create mode 100644 tools/food/get_menu_item_details.py create mode 100644 tools/food/place_order.py diff --git a/tools/__init__.py b/tools/__init__.py index 4743369..b960fa8 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -22,6 +22,12 @@ from .ecommerce.get_order import get_order from .ecommerce.track_package import track_package from .ecommerce.list_orders import list_orders +from .food.get_menu import get_menu +from .food.get_menu_item_details import get_menu_item_details +from .food.add_to_cart import add_to_cart +from .food.place_order import place_order +from .food.check_order_status import check_order_status + from .give_hint import give_hint from .guess_location import guess_location @@ -67,6 +73,16 @@ def get_handler(tool_name: str): return track_package if tool_name == "ListOrders": return list_orders + if tool_name == "GetMenu": + return get_menu + if tool_name == "GetMenuItemDetails": + return get_menu_item_details + if tool_name == "AddToCart": + return add_to_cart + if tool_name == "PlaceOrder": + return place_order + if tool_name == "CheckOrderStatus": + return check_order_status if tool_name == "GiveHint": return give_hint if tool_name == "GuessLocation": diff --git a/tools/data/food_ordering_data.json b/tools/data/food_ordering_data.json new file mode 100644 index 0000000..625a9f9 --- /dev/null +++ b/tools/data/food_ordering_data.json @@ -0,0 +1,122 @@ +{ + "restaurants": [ + { + "id": "rest_001", + "name": "Tony's Pizza Palace", + "menu": [ + { + "id": "item_001", + "name": "Margherita Pizza", + "category": "Pizza", + "price": 14.99, + "description": "Fresh mozzarella, tomato sauce, basil", + "available": true + }, + { + "id": "item_002", + "name": "Pepperoni Pizza", + "category": "Pizza", + "price": 16.99, + "description": "Classic pepperoni with mozzarella and tomato sauce", + "available": true + }, + { + "id": "item_003", + "name": "Caesar Salad", + "category": "Salad", + "price": 9.99, + "description": "Romaine lettuce, parmesan, croutons, caesar dressing", + "available": true + }, + { + "id": "item_004", + "name": "Garlic Bread", + "category": "Sides", + "price": 5.99, + "description": "Fresh baked bread with garlic butter", + "available": true + }, + { + "id": "item_005", + "name": "Tiramisu", + "category": "Dessert", + "price": 7.99, + "description": "Classic Italian dessert with coffee and mascarpone", + "available": true + } + ] + } + ], + "carts": { + "steve@example.com": { + "restaurant_id": "rest_001", + "items": [] + } + }, + "orders": [ + { + "id": "order_001", + "customer_email": "john.doe@example.com", + "restaurant_id": "rest_001", + "items": [ + { + "item_id": "item_001", + "quantity": 1, + "price": 14.99 + }, + { + "item_id": "item_004", + "quantity": 2, + "price": 5.99 + } + ], + "total": 26.97, + "status": "delivered", + "order_date": "2025-05-29T18:30:00Z", + "estimated_delivery": "2025-05-29T19:15:00Z", + "actual_delivery": "2025-05-29T19:12:00Z" + }, + { + "id": "order_002", + "customer_email": "jane.smith@example.com", + "restaurant_id": "rest_001", + "items": [ + { + "item_id": "item_002", + "quantity": 1, + "price": 16.99 + } + ], + "total": 16.99, + "status": "preparing", + "order_date": "2025-05-30T12:00:00Z", + "estimated_delivery": "2025-05-30T12:45:00Z" + }, + { + "id": "order_58539a70", + "customer_email": "steve@example.com", + "restaurant_id": "rest_001", + "items": [ + { + "item_id": "item_001", + "quantity": 1, + "price": 14.99 + }, + { + "item_id": "item_002", + "quantity": 1, + "price": 16.99 + }, + { + "item_id": "item_004", + "quantity": 1, + "price": 5.99 + } + ], + "total": 37.97, + "status": "preparing", + "order_date": "2025-05-30T20:28:18.444162Z", + "estimated_delivery": "2025-05-30T20:58:18.444169Z" + } + ] +} \ No newline at end of file diff --git a/tools/food/add_to_cart.py b/tools/food/add_to_cart.py new file mode 100644 index 0000000..6ae03fc --- /dev/null +++ b/tools/food/add_to_cart.py @@ -0,0 +1,63 @@ +from pathlib import Path +import json + +def add_to_cart(args: dict) -> dict: + customer_email = args.get("customer_email") + item_id = args.get("item_id") + quantity = int(args.get("quantity", 1)) + restaurant_id = args.get("restaurant_id", "rest_001") + + file_path = Path(__file__).resolve().parent.parent / "data" / "food_ordering_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + + # Find the item to get its price + item_price = None + item_name = None + for restaurant in data["restaurants"]: + if restaurant["id"] == restaurant_id: + for item in restaurant["menu"]: + if item["id"] == item_id: + item_price = item["price"] + item_name = item["name"] + break + + if item_price is None: + return {"error": f"Item {item_id} not found."} + + # Initialize cart if it doesn't exist + if customer_email not in data["carts"]: + data["carts"][customer_email] = { + "restaurant_id": restaurant_id, + "items": [] + } + + # Check if item already in cart + cart = data["carts"][customer_email] + existing_item = None + for cart_item in cart["items"]: + if cart_item["item_id"] == item_id: + existing_item = cart_item + break + + if existing_item: + existing_item["quantity"] += quantity + else: + cart["items"].append({ + "item_id": item_id, + "quantity": quantity, + "price": item_price + }) + + # Save back to file + with open(file_path, "w") as file: + json.dump(data, file, indent=2) + + return { + "status": "success", + "message": f"Added {quantity} x {item_name} to cart", + "cart": cart + } \ No newline at end of file diff --git a/tools/food/check_order_status.py b/tools/food/check_order_status.py new file mode 100644 index 0000000..f8939bf --- /dev/null +++ b/tools/food/check_order_status.py @@ -0,0 +1,28 @@ +from pathlib import Path +import json + +def check_order_status(args: dict) -> dict: + order_id = args.get("order_id") + + file_path = Path(__file__).resolve().parent.parent / "data" / "food_ordering_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + + orders = data["orders"] + + for order in orders: + if order["id"] == order_id: + return { + "order_id": order["id"], + "status": order["status"], + "order_date": order["order_date"], + "estimated_delivery": order["estimated_delivery"], + "actual_delivery": order.get("actual_delivery"), + "total": order["total"], + "items": order["items"] + } + + return {"error": f"Order {order_id} not found."} \ No newline at end of file diff --git a/tools/food/get_menu.py b/tools/food/get_menu.py new file mode 100644 index 0000000..ec71ab5 --- /dev/null +++ b/tools/food/get_menu.py @@ -0,0 +1,23 @@ +from pathlib import Path +import json + +def get_menu(args: dict) -> dict: + restaurant_id = args.get("restaurant_id", "rest_001") + + file_path = Path(__file__).resolve().parent.parent / "data" / "food_ordering_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + + restaurants = data["restaurants"] + + for restaurant in restaurants: + if restaurant["id"] == restaurant_id: + return { + "restaurant_name": restaurant["name"], + "menu": restaurant["menu"] + } + + return {"error": f"Restaurant {restaurant_id} not found."} \ No newline at end of file diff --git a/tools/food/get_menu_item_details.py b/tools/food/get_menu_item_details.py new file mode 100644 index 0000000..6df4218 --- /dev/null +++ b/tools/food/get_menu_item_details.py @@ -0,0 +1,23 @@ +from pathlib import Path +import json + +def get_menu_item_details(args: dict) -> dict: + item_id = args.get("item_id") + restaurant_id = args.get("restaurant_id", "rest_001") + + file_path = Path(__file__).resolve().parent.parent / "data" / "food_ordering_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + + restaurants = data["restaurants"] + + for restaurant in restaurants: + if restaurant["id"] == restaurant_id: + for item in restaurant["menu"]: + if item["id"] == item_id: + return item + + return {"error": f"Menu item {item_id} not found."} \ No newline at end of file diff --git a/tools/food/place_order.py b/tools/food/place_order.py new file mode 100644 index 0000000..560b597 --- /dev/null +++ b/tools/food/place_order.py @@ -0,0 +1,57 @@ +from pathlib import Path +import json +import uuid +from datetime import datetime, timedelta + +def place_order(args: dict) -> dict: + customer_email = args.get("customer_email") + + file_path = Path(__file__).resolve().parent.parent / "data" / "food_ordering_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + + # Check if cart exists + if customer_email not in data["carts"] or not data["carts"][customer_email]["items"]: + return {"error": "Cart is empty. Please add items to cart first."} + + cart = data["carts"][customer_email] + + # Calculate total + total = sum(item["price"] * item["quantity"] for item in cart["items"]) + + # Create order + order_id = f"order_{str(uuid.uuid4())[:8]}" + order_date = datetime.now().isoformat() + "Z" + estimated_delivery = (datetime.now() + timedelta(minutes=30)).isoformat() + "Z" + + new_order = { + "id": order_id, + "customer_email": customer_email, + "restaurant_id": cart["restaurant_id"], + "items": cart["items"], + "total": round(total, 2), + "status": "preparing", + "order_date": order_date, + "estimated_delivery": estimated_delivery + } + + # Add order to data + data["orders"].append(new_order) + + # Clear cart + data["carts"][customer_email] = {"restaurant_id": cart["restaurant_id"], "items": []} + + # Save back to file + with open(file_path, "w") as file: + json.dump(data, file, indent=2) + + return { + "status": "success", + "order_id": order_id, + "total": round(total, 2), + "estimated_delivery": estimated_delivery, + "message": "Order placed successfully!" + } \ No newline at end of file diff --git a/tools/goal_registry.py b/tools/goal_registry.py index 7de7ca4..98b4bc0 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -454,6 +454,50 @@ goal_ecomm_list_orders = AgentGoal( ), ) +# ----- Food Ordering Goal ----- +goal_food_ordering = AgentGoal( + id="goal_food_ordering", + category_tag="food", + agent_name="Food Ordering Assistant", + agent_friendly_description="Order food from Tony's Pizza Palace. Browse menu, add items to cart, and place orders.", + tools=[ + tool_registry.food_get_menu_tool, + tool_registry.food_get_menu_item_details_tool, + tool_registry.food_add_to_cart_tool, + tool_registry.food_place_order_tool, + tool_registry.food_check_order_status_tool, + ], + description="The user wants to order food from Tony's Pizza Palace. Help them browse the menu, learn about menu items, add items to their cart, and place an order. To assist with that goal, help the user gather args for these tools in order: " + "1. GetMenu: Show the restaurant menu. This tool is optional if the user already knows what they want. " + "2. GetMenuItemDetails: Get details about specific menu items. This tool is optional and can be used multiple times. " + "3. AddToCart: Add menu items to the customer's cart. This tool can be used multiple times to add different items. " + "4. PlaceOrder: Place the order for items in the cart. " + "5. CheckOrderStatus: Check the status of a placed order. This tool is optional and used after placing an order.", + starter_prompt=starter_prompt_generic, + example_conversation_history="\n ".join( + [ + "user: I'd like to order some food", + "agent: Great! I can help you order food from Tony's Pizza Palace. Would you like to see the menu first?", + "user: Yes, please show me the menu", + "user_confirmed_tool_run: ", + "tool_result: {'restaurant_name': 'Tony\\'s Pizza Palace', 'menu': [{'id': 'item_001', 'name': 'Margherita Pizza', 'category': 'Pizza', 'price': 14.99, 'description': 'Fresh mozzarella, tomato sauce, basil', 'available': True}, {'id': 'item_002', 'name': 'Pepperoni Pizza', 'category': 'Pizza', 'price': 16.99, 'description': 'Classic pepperoni with mozzarella and tomato sauce', 'available': True}]}", + "agent: Here's the menu from Tony's Pizza Palace: \n" + "Pizza: \n" + "- Margherita Pizza ($14.99): Fresh mozzarella, tomato sauce, basil \n" + "- Pepperoni Pizza ($16.99): Classic pepperoni with mozzarella and tomato sauce \n" + "What would you like to add to your cart? I'll need your email address to create your order.", + "user: I'd like a Margherita Pizza. My email is john.doe@example.com", + "user_confirmed_tool_run: ", + "tool_result: {'status': 'success', 'message': 'Added 1 x Margherita Pizza to cart', 'cart': {'restaurant_id': 'rest_001', 'items': [{'item_id': 'item_001', 'quantity': 1, 'price': 14.99}]}}", + "agent: Perfect! I've added 1 Margherita Pizza to your cart. Would you like to add anything else or are you ready to place your order?", + "user: I'm ready to place the order", + "user_confirmed_tool_run: ", + "tool_result: {'status': 'success', 'order_id': 'order_12345678', 'total': 14.99, 'estimated_delivery': '2025-05-30T13:30:00Z', 'message': 'Order placed successfully!'}", + "agent: Order placed successfully! Your order ID is order_12345678 and the total is $14.99. Your food should be delivered by 1:30 PM today. You can check your order status anytime using the order ID.", + ] + ), +) + # Add the goals to a list for more generic processing, like listing available agents goal_list: List[AgentGoal] = [] goal_list.append(goal_choose_agent_type) @@ -468,6 +512,7 @@ goal_list.append(goal_fin_move_money) goal_list.append(goal_fin_loan_application) goal_list.append(goal_ecomm_list_orders) goal_list.append(goal_ecomm_order_status) +goal_list.append(goal_food_ordering) # for multi-goal, just set list agents as the last tool diff --git a/tools/tool_registry.py b/tools/tool_registry.py index bff6983..54cf4e5 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -397,3 +397,89 @@ ecomm_track_package = ToolDefinition( ), ], ) + +# ----- Food Ordering Use Case Tools ----- +food_get_menu_tool = ToolDefinition( + name="GetMenu", + description="Get the menu for a restaurant. Defaults to Tony's Pizza Palace if no restaurant specified.", + arguments=[ + ToolArgument( + name="restaurant_id", + type="string", + description="ID of the restaurant (defaults to rest_001 for Tony's Pizza Palace)", + ), + ], +) + +food_get_menu_item_details_tool = ToolDefinition( + name="GetMenuItemDetails", + description="Get detailed information about a specific menu item.", + arguments=[ + ToolArgument( + name="item_id", + type="string", + description="ID of the menu item to get details for", + ), + ToolArgument( + name="restaurant_id", + type="string", + description="ID of the restaurant (defaults to rest_001 for Tony's Pizza Palace)", + ), + ], +) + +food_add_to_cart_tool = ToolDefinition( + name="AddToCart", + description="Add a menu item to the customer's cart.", + arguments=[ + ToolArgument( + name="customer_email", + type="string", + description="Email address of the customer", + ), + ToolArgument( + name="item_id", + type="string", + description="ID of the menu item to add to cart", + ), + ToolArgument( + name="quantity", + type="number", + description="Quantity of the item to add (defaults to 1)", + ), + ToolArgument( + name="restaurant_id", + type="string", + description="ID of the restaurant (defaults to rest_001 for Tony's Pizza Palace)", + ), + ], +) + +food_place_order_tool = ToolDefinition( + name="PlaceOrder", + description="Place an order for the items in the customer's cart.", + arguments=[ + ToolArgument( + name="customer_email", + type="string", + description="Email address of the customer", + ), + ToolArgument( + name="userConfirmation", + type="string", + description="Indication of user's desire to place the order", + ), + ], +) + +food_check_order_status_tool = ToolDefinition( + name="CheckOrderStatus", + description="Check the status of a food order.", + arguments=[ + ToolArgument( + name="order_id", + type="string", + description="ID of the order to check status for", + ), + ], +)