Browse Source

Merge pull request #306 from ariel1985/main

Add eCommerce Assistant notebook for product price retrieval week2
pull/312/merge
Ed Donner 4 weeks ago committed by GitHub
parent
commit
67b5e3c043
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 653
      week2/community-contributions/day4-ecommerce-project-fullyCustomiz.ipynb
  2. 293
      week2/community-contributions/week2-commerce-chatbot-assistant-and-agent.ipynb

653
week2/community-contributions/day4-ecommerce-project-fullyCustomiz.ipynb

@ -0,0 +1,653 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "ddfa9ae6-69fe-444a-b994-8c4c5970a7ec",
"metadata": {},
"source": [
"# 🛠 Project – Art-Tech Store AI Assistant\n",
"\n",
"## 🛍 Product Availability\n",
"- Check availability of **printers** and **printer papers** with:\n",
" - Product name, price, brand, type (e.g., laser/inkjet), and stock status.\n",
"- Alerts user if a product is out of stock.\n",
"\n",
"## 🧭 Guided Shopping Experience\n",
"- Guides users through:\n",
" 1. Choosing product category (printer or paper)\n",
" 2. Filtering options (brand, price range, type)\n",
" 3. Adding selected products to cart\n",
"- Ensures correct input for smooth shopping flow.\n",
"\n",
"## 🧾 Receipt Generation\n",
"- Creates a unique receipt file: `customerName_orderNumber.txt`\n",
"- Receipt includes:\n",
" - Customer name and contact\n",
" - Product details (name, price, quantity)\n",
" - Total cost and order summary\n",
"\n",
"## 📦 Generate Order Summary Report\n",
"- Summarizes all purchases into a single file: `order_summary.txt`\n",
"- Useful for inventory and sales review\n",
"\n",
"## 🎯 Product Recommendation\n",
"- Recommends:\n",
" - Printers based on paper type, usage (home/office), or brand preference\n",
" - Compatible paper based on selected printer\n",
"\n",
"## 💬 Interactive Chat Interface\n",
"- Real-time conversation via **Gradio**\n",
"- Polite, helpful answers to product-related questions\n",
"\n",
"## 🛠 Modular Tool Support\n",
"- Integrated tools for:\n",
" - Checking product availability\n",
" - Adding to cart and generating receipts\n",
" - Creating summary reports\n",
"- Easily extendable for:\n",
" - Promotions\n",
" - Customer reviews\n",
" - Delivery tracking\n",
"\n",
"## 🛡 Error Handling\n",
"- Validates user inputs (e.g., product name, quantity)\n",
"- Graceful messages to guide user and prevent mistakes\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "747e8786-9da8-4342-b6c9-f5f69c2e22ae",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"import random\n",
"from dotenv import load_dotenv\n",
"import gradio as gr\n",
"from openai import OpenAI\n",
"\n",
"load_dotenv()\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
"\n",
"# MODEL = \"gpt-4o-mini\"\n",
"MODEL = \"gpt-3.5-turbo\"\n",
"openai = OpenAI()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e6072536-eee1-4f87-9f03-8dc88dc04f1a",
"metadata": {},
"outputs": [],
"source": [
"# Using local LLM (that can't even handle basic greeting like Hi!!\n",
"\n",
"# MODEL = \"llama3.2\"\n",
"# openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5fe5f5d7-0bd1-41a2-a654-59b587882f22",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 1) System Prompt\n",
"###############################################################################\n",
"system_message = (\n",
" \"You are a helpful assistant for an online store called art-tech.store that sells printers and printer papers.\\n\\n\"\n",
" \"When the user wants to purchase a product, follow these steps:\\n\"\n",
" \"1. Ask whether they are interested in printers or printer papers.\\n\"\n",
" \"2. Ask for filtering preferences (e.g., brand, price range, type).\\n\"\n",
" \"3. Call the function 'check_product_availability' with the selected category and filters.\\n\"\n",
" \" - If it returns an empty list, say: 'No products found for your selection.'\\n\"\n",
" \" - If it returns products, list them EXACTLY, in a numbered list, showing name, price, brand, and availability.\\n\"\n",
" \"4. Wait for the user to select a product by number and quantity.\\n\"\n",
" \"5. Ask for customer first name and contact info.\\n\"\n",
" \"6. Then call 'add_to_cart_and_generate_receipt' to confirm and show the user the receipt and order details.\\n\\n\"\n",
" \"You also have a tool 'generate_report' which summarizes ALL purchases in a single file.\\n\\n\"\n",
" \"IMPORTANT:\\n\"\n",
" \"- Always call 'check_product_availability' if user mentions a new category or changes filters.\\n\"\n",
" \"- Do not invent products or details. Use only what the function calls return.\\n\"\n",
" \"- Every time an order is placed, produce a new receipt file named customerName_orderNumber.txt.\\n\"\n",
" \"- If no matching products are found, say so.\\n\"\n",
" \"- If the user wants a full order summary, call 'generate_report' with no arguments.\\n\"\n",
" \"If you don't know something, say so.\\n\"\n",
" \"Keep answers short and courteous.\\n\"\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "61a2a15d-b559-4844-b377-6bd5cb4949f6",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 2) Mini Printer Availability with Price & Stock\n",
"###############################################################################\n",
"product_availability = {\n",
" \"mini_printers\": [\n",
" {\n",
" \"name\": \"Phomemo M110 מדפסת מדבקות חכמה\",\n",
" \"brand\": \"Phomemo\",\n",
" \"price\": \"₪300\", # Update if pricing is known\n",
" \"type\": \"Label Printer\",\n",
" \"availability\": \"360,745 in stock (24 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"Niimbot B1 Label Printer\",\n",
" \"brand\": \"Niimbot\",\n",
" \"price\": \"₪350\",\n",
" \"type\": \"Portable Thermal Label Printer\",\n",
" \"availability\": \"13,029 in stock (18 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"Niimbot B21 Mini Portable Thermal Label Printer\",\n",
" \"brand\": \"Niimbot\",\n",
" \"price\": \"₪500\",\n",
" \"type\": \"Adhesive Sticker Printer\",\n",
" \"availability\": \"141 in stock (12 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"Dolewa D3 Portable Mini Printer\",\n",
" \"brand\": \"Dolewa\",\n",
" \"price\": \"₪450\",\n",
" \"type\": \"Thermal Photo & Label Printer\",\n",
" \"availability\": \"336 in stock (6 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"PrintPro Mini מדפסת כיס חכמה\",\n",
" \"brand\": \"PrintPro\",\n",
" \"price\": \"₪550\",\n",
" \"type\": \"Mini Pocket Printer\",\n",
" \"availability\": \"336 in stock (6 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"מיני מדפסת טרמית מעוצבת לילדים\",\n",
" \"brand\": \"Art-Tech\",\n",
" \"price\": \"₪200\",\n",
" \"type\": \"Kids Thermal Printer\",\n",
" \"availability\": \"62 in stock (11 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"Children Digital Camera Instant Print\",\n",
" \"brand\": \"Art-Tech\",\n",
" \"price\": \"₪250\",\n",
" \"type\": \"Photo Printing Camera with 32G Memory Card\",\n",
" \"availability\": \"160 in stock (3 variants)\"\n",
" }\n",
" ],\n",
" \"mini_printer_papers\": [\n",
" {\n",
" \"name\": \"HP Printer Paper 8.5x11, 500 Sheets\", # example only\n",
" \"brand\": \"HP\",\n",
" \"price\": \"$9.99\",\n",
" \"type\": \"Standard\",\n",
" \"availability\": \"In stock\"\n",
" },\n",
" {\n",
" \"name\": \"Mini Printer Paper 57*25mm Color Sticker\",\n",
" \"brand\": \"Art-Tech\",\n",
" \"price\": \"₪70\",\n",
" \"type\": \"Self-adhesive Color Label Paper\",\n",
" \"availability\": \"71,996 in stock (9 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"מדבקות שקופות למדפסת טרמית\",\n",
" \"brand\": \"Art-Tech\",\n",
" \"price\": \"₪55\",\n",
" \"type\": \"Transparent Labels\",\n",
" \"availability\": \"11,762 in stock (12 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"גלילי נייר מדבקה\",\n",
" \"brand\": \"Art-Tech\",\n",
" \"price\": \"₪40\",\n",
" \"type\": \"Sticker Paper Rolls\",\n",
" \"availability\": \"42 in stock (4 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"Niimbot B21/B1/B3S Thermal Label Sticker Paper\",\n",
" \"brand\": \"Niimbot\",\n",
" \"price\": \"₪55\",\n",
" \"type\": \"Printable White Label Paper 20–50mm\",\n",
" \"availability\": \"1,342 in stock (14 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"Mini Printer Sticker Paper 25X57mm\",\n",
" \"brand\": \"Paperang-compatible\",\n",
" \"price\": \"₪65\",\n",
" \"type\": \"Color Self-Adhesive Thermal Rolls\",\n",
" \"availability\": \"3,023 in stock (20 variants)\"\n",
" },\n",
" {\n",
" \"name\": \"3/5/10 NiiMBOT White Label Paper Rolls\",\n",
" \"brand\": \"Niimbot\",\n",
" \"price\": \"₪40\",\n",
" \"type\": \"Waterproof Self-adhesive Rolls\",\n",
" \"availability\": \"1,400 in stock (9 variants)\"\n",
" }\n",
" ]\n",
"}\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0696acb1-0b05-4dc2-80d5-771be04f1fb2",
"metadata": {},
"outputs": [],
"source": [
"# A global list of flight bookings\n",
"flight_bookings = []\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "80ca4e09-6287-4d3f-997d-fa6afbcf6c85",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 3) Helper Functions for Art-Tech Store\n",
"###############################################################################\n",
"\n",
"product_orders = []\n",
"\n",
"def check_product_availability(category: str, filters: dict = None):\n",
" \"\"\"\n",
" Return list of products in the given category from 'product_availability'.\n",
" Optionally filter by brand, type, etc.\n",
" \"\"\"\n",
" print(f\"[TOOL] check_product_availability({category}, {filters=})\")\n",
" category = category.lower()\n",
" products = product_availability.get(category, [])\n",
" \n",
" if filters:\n",
" for key, val in filters.items():\n",
" products = [p for p in products if p.get(key, \"\").lower() == val.lower()]\n",
" return products\n",
"\n",
"\n",
"def add_to_cart_and_generate_receipt(customer_name: str, contact: str, product: dict, quantity: int, order_number: int):\n",
" \"\"\"\n",
" Create a text file: customerName_orderNumber.txt containing order details.\n",
" \"\"\"\n",
" safe_name = customer_name.replace(\" \", \"_\")\n",
" filename = f\"{safe_name}_{order_number}.txt\"\n",
"\n",
" content = (\n",
" \"Art-Tech Store Receipt\\n\"\n",
" \"=======================\\n\"\n",
" f\"Order # : {order_number}\\n\"\n",
" f\"Customer : {customer_name}\\n\"\n",
" f\"Contact : {contact}\\n\"\n",
" f\"Product : {product['name']}\\n\"\n",
" f\"Brand : {product['brand']}\\n\"\n",
" f\"Type : {product.get('type', 'N/A')}\\n\"\n",
" f\"Price : {product['price']}\\n\"\n",
" f\"Quantity : {quantity}\\n\"\n",
" f\"Availability: {product['availability']}\\n\"\n",
" )\n",
" with open(filename, \"w\") as f:\n",
" f.write(content)\n",
"\n",
" print(f\"[TOOL] Receipt file generated => {filename}\")\n",
" return filename\n",
"\n",
"\n",
"def place_order(category, product_index, quantity, customer_name, contact_info):\n",
" \"\"\"\n",
" Places an order for a product by index in the filtered list.\n",
" \"\"\"\n",
" print(f\"[TOOL] place_order({category=}, {product_index=}, {quantity=})\")\n",
"\n",
" try:\n",
" idx = int(product_index)\n",
" except ValueError:\n",
" return \"Error: Product option number is not a valid integer.\"\n",
"\n",
" products = product_availability.get(category.lower(), [])\n",
" if not products:\n",
" return f\"Error: No products found in category '{category}'.\"\n",
"\n",
" pick = idx - 1\n",
" if pick < 0 or pick >= len(products):\n",
" return f\"Error: Invalid product option #{idx} for category '{category}'.\"\n",
"\n",
" selected_product = products[pick]\n",
"\n",
" order = {\n",
" \"category\": category,\n",
" \"product\": selected_product[\"name\"],\n",
" \"brand\": selected_product[\"brand\"],\n",
" \"type\": selected_product.get(\"type\", \"\"),\n",
" \"price\": selected_product[\"price\"],\n",
" \"quantity\": quantity,\n",
" \"customer_name\": customer_name,\n",
" \"contact\": contact_info,\n",
" }\n",
" product_orders.append(order)\n",
"\n",
" order_number = len(product_orders)\n",
" receipt_filename = add_to_cart_and_generate_receipt(customer_name, contact_info, selected_product, quantity, order_number)\n",
"\n",
" confirmation = (\n",
" f\"Order #{order_number} confirmed for {customer_name}. \"\n",
" f\"{selected_product['name']} x{quantity}. Receipt saved to {receipt_filename}.\"\n",
" )\n",
" print(f\"[TOOL] {confirmation}\")\n",
" return confirmation\n",
"\n",
"\n",
"def generate_report():\n",
" \"\"\"\n",
" Summarize ALL orders in a single file called order_summary.txt.\n",
" \"\"\"\n",
" print(f\"[TOOL] generate_report called.\")\n",
"\n",
" report_content = \"Art-Tech Store Order Summary Report\\n\"\n",
" report_content += \"===================================\\n\"\n",
"\n",
" if not product_orders:\n",
" report_content += \"No orders found.\\n\"\n",
" else:\n",
" for i, order in enumerate(product_orders, start=1):\n",
" report_content += (\n",
" f\"Order # : {i}\\n\"\n",
" f\"Customer : {order['customer_name']}\\n\"\n",
" f\"Contact : {order['contact']}\\n\"\n",
" f\"Product : {order['product']}\\n\"\n",
" f\"Brand : {order['brand']}\\n\"\n",
" f\"Type : {order['type']}\\n\"\n",
" f\"Price : {order['price']}\\n\"\n",
" f\"Quantity : {order['quantity']}\\n\"\n",
" \"-------------------------\\n\"\n",
" )\n",
"\n",
" filename = \"order_summary.txt\"\n",
" with open(filename, \"w\") as f:\n",
" f.write(report_content)\n",
"\n",
" msg = f\"Summary report generated => {filename}\"\n",
" print(f\"[TOOL] {msg}\")\n",
" return msg\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39fb9008",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 4) Tools JSON Schemas for Art-Tech Store\n",
"###############################################################################\n",
"price_function = {\n",
" \"name\": \"get_product_price\",\n",
" \"description\": \"Get the price of a product (not strictly needed now).\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"category\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Product category such as 'mini_printers' or 'mini_printer_papers'.\",\n",
" },\n",
" \"product_name\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Name of the product to check price for.\",\n",
" },\n",
" },\n",
" \"required\": [\"category\", \"product_name\"],\n",
" },\n",
"}\n",
"\n",
"availability_function = {\n",
" \"name\": \"check_product_availability\",\n",
" \"description\": (\n",
" \"Check availability of products in a category. \"\n",
" \"Returns a list of {name, brand, price, type, availability}.\"\n",
" ),\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"category\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Category of products to check (e.g., 'mini_printers').\",\n",
" },\n",
" \"filters\": {\n",
" \"type\": \"object\",\n",
" \"description\": \"Optional filters like brand or type.\",\n",
" },\n",
" },\n",
" \"required\": [\"category\"],\n",
" },\n",
"}\n",
"\n",
"book_function = {\n",
" \"name\": \"place_order\",\n",
" \"description\": (\n",
" \"Place an order using an index for the chosen product. \"\n",
" \"Generates a unique receipt file customerName_{orderNumber}.txt.\"\n",
" ),\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"category\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Product category (e.g., 'mini_printers').\",\n",
" },\n",
" \"product_index\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"1-based index of selected product from availability list.\",\n",
" },\n",
" \"quantity\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Quantity to order.\",\n",
" },\n",
" \"customer_name\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Customer's full name.\",\n",
" },\n",
" \"contact_info\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Customer's contact information (email or phone).\",\n",
" },\n",
" },\n",
" \"required\": [\"category\", \"product_index\", \"quantity\", \"customer_name\", \"contact_info\"],\n",
" },\n",
"}\n",
"\n",
"report_function = {\n",
" \"name\": \"generate_report\",\n",
" \"description\": (\n",
" \"Generates a summary report of ALL orders in order_summary.txt.\"\n",
" ),\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {},\n",
" \"required\": [],\n",
" },\n",
"}\n",
"\n",
"tools = [\n",
" {\"type\": \"function\", \"function\": price_function},\n",
" {\"type\": \"function\", \"function\": availability_function},\n",
" {\"type\": \"function\", \"function\": book_function},\n",
" {\"type\": \"function\", \"function\": report_function},\n",
"]\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1f003836",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 5) Handle Tool Calls for Art-Tech Store\n",
"###############################################################################\n",
"def handle_tool_call(message):\n",
" \"\"\"\n",
" The LLM can request to call a function in 'tools'. We parse the JSON arguments\n",
" and run the corresponding Python function. Then we return a 'tool' message with the result.\n",
" \"\"\"\n",
" tool_call = message.tool_calls[0]\n",
" fn_name = tool_call.function.name\n",
" args = json.loads(tool_call.function.arguments)\n",
"\n",
" if fn_name == \"get_product_price\":\n",
" category = args.get(\"category\")\n",
" product_name = args.get(\"product_name\")\n",
" products = product_availability.get(category.lower(), [])\n",
" price = \"Not found\"\n",
" for p in products:\n",
" if p[\"name\"].lower() == product_name.lower():\n",
" price = p[\"price\"]\n",
" break\n",
" response_content = {\"category\": category, \"product_name\": product_name, \"price\": price}\n",
"\n",
" elif fn_name == \"check_product_availability\":\n",
" category = args.get(\"category\")\n",
" filters = args.get(\"filters\", {})\n",
" products = check_product_availability(category, filters)\n",
" response_content = {\"category\": category, \"availability\": products}\n",
"\n",
" elif fn_name == \"place_order\":\n",
" category = args.get(\"category\")\n",
" product_index = args.get(\"product_index\")\n",
" quantity = args.get(\"quantity\")\n",
" customer_name = args.get(\"customer_name\")\n",
" contact_info = args.get(\"contact_info\")\n",
"\n",
" confirmation = place_order(category, product_index, quantity, customer_name, contact_info)\n",
" response_content = {\n",
" \"category\": category,\n",
" \"product_index\": product_index,\n",
" \"quantity\": quantity,\n",
" \"customer_name\": customer_name,\n",
" \"contact_info\": contact_info,\n",
" \"confirmation\": confirmation,\n",
" }\n",
"\n",
" elif fn_name == \"generate_report\":\n",
" msg = generate_report()\n",
" response_content = {\"report\": msg}\n",
"\n",
" else:\n",
" response_content = {\"error\": f\"Unknown tool: {fn_name}\"}\n",
"\n",
" return {\n",
" \"role\": \"tool\",\n",
" \"content\": json.dumps(response_content),\n",
" \"tool_call_id\": tool_call.id,\n",
" }, args\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f6b34b32",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 6) Main Chat Function for Art-Tech Store\n",
"###############################################################################\n",
"def chat(message, history):\n",
" \"\"\"\n",
" The main chat loop that handles the conversation with the user,\n",
" passing 'tools' definitions to the LLM for function calling.\n",
" \"\"\"\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
"\n",
" try:\n",
" response = openai.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages,\n",
" tools=tools\n",
" )\n",
"\n",
" # If the LLM requests a function call, handle it\n",
" while response.choices[0].finish_reason == \"tool_calls\":\n",
" msg = response.choices[0].message\n",
" print(f\"[INFO] Tool call requested: {msg.tool_calls[0]}\")\n",
" tool_response, tool_args = handle_tool_call(msg)\n",
" print(f\"[INFO] Tool response: {tool_response}\")\n",
"\n",
" # Add both the LLM's request and our tool response to the conversation\n",
" messages.append(msg)\n",
" messages.append(tool_response)\n",
"\n",
" # Re-send updated conversation to get final or next step\n",
" response = openai.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages\n",
" )\n",
"\n",
" # Return normal text response (finish_reason = \"stop\")\n",
" return response.choices[0].message.content\n",
"\n",
" except Exception as e:\n",
" print(f\"[ERROR] {e}\")\n",
" return \"I'm sorry, something went wrong while processing your request.\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cea4b097",
"metadata": {},
"outputs": [],
"source": [
"###############################################################################\n",
"# 7) Launch Gradio\n",
"###############################################################################\n",
"gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b39d5a6",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

293
week2/community-contributions/week2-commerce-chatbot-assistant-and-agent.ipynb

@ -0,0 +1,293 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "e3a5643a-c247-4a9b-8c57-ec9b1e89c088",
"metadata": {},
"source": [
"# Week 2 - eCommerce Assistant for products price from dictionary\n",
"\n",
"An eCommerce assitant that can get a product price\n",
"\n",
"Gradio for chat box"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "756573b3-72b2-4102-a773-91c278e5c4fd",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# !ollama pull llama3.2"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "57ae8d30-f7aa-47a3-bab8-b7002e87a8f7",
"metadata": {},
"outputs": [],
"source": [
"# imports\n",
"\n",
"import os\n",
"import json\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
"import gradio as gr"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ef7f8b2b-1d6a-4bbd-858a-be187ccfc02a",
"metadata": {},
"outputs": [],
"source": [
"# Initialization\n",
"\n",
"load_dotenv(override=True)\n",
"\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"MODEL = \"gpt-4o-mini\"\n",
"openai = OpenAI()\n",
"\n",
"# As an alternative, if you'd like to use Ollama instead of OpenAI\n",
"# Check that Ollama is running for you locally (see week1/day2 exercise) then uncomment these next 2 lines\n",
"# MODEL = \"llama3.2\"\n",
"# openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b46dd52-8a3c-42d1-ac24-59f5eb5aaba1",
"metadata": {},
"outputs": [],
"source": [
"system_message = \"You are a helpful assistant for an online store called CommerceAI. \"\n",
"system_message += \"Give short, courteous answers, no more than 1 sentence. \"\n",
"system_message += \"Always be accurate. If you don't know the answer, say so.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31a6431b-215d-4f46-b813-971d8af7e034",
"metadata": {},
"outputs": [],
"source": [
"# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n",
"\n",
"def chat(message, history):\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
" return response.choices[0].message.content\n",
"\n",
"gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
},
{
"cell_type": "markdown",
"id": "d3586bfb-acc3-4b5e-95be-02120b696f98",
"metadata": {},
"source": [
"## Tools\n",
"\n",
"Tools are an incredibly powerful feature provided by the frontier LLMs.\n",
"\n",
"With tools, you can write a function, and have the LLM call that function as part of its response.\n",
"\n",
"Sounds almost spooky.. we're giving it the power to run code on our machine?\n",
"\n",
"Well, kinda."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c9ac43e8-9880-44f6-b03a-6d1ab05bbb94",
"metadata": {},
"outputs": [],
"source": [
"# Let's start by making a useful function\n",
"\n",
"items_prices = {f\"item{i}\": f\"{i*100}\" for i in range(1,6)}\n",
"\n",
"items_prices = {\"printer\": \"$500\", \"paper\": \"$10\", \"mini printer\": \"$50\", \"label printer\": \"$60\", \"sticker-paper\": \"$5\"}\n",
"\n",
"def get_item_price(product):\n",
" print(f\"Tool get_item_price called for {product}\")\n",
" item = product.lower()\n",
" return items_prices.get(item, \"Unknown\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "88d249f7-787d-4750-b5b9-7df108da1b57",
"metadata": {},
"outputs": [],
"source": [
"items_prices"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ef3c3897-9a57-4f04-b5d0-f9ac8bb02d00",
"metadata": {},
"outputs": [],
"source": [
"get_item_price(\"mini printer\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "511ef9b8-bec0-4f14-b647-057e14c849cc",
"metadata": {},
"outputs": [],
"source": [
"# There's a particular dictionary structure that's required to describe our function:\n",
"\n",
"price_function = {\n",
" \"name\": \"get_item_price\",\n",
" \"description\": \"Get the price of an item in the store. \\\n",
" Call this whenever you need to know the store item price , \\\n",
" for example when a customer asks 'How much is a mini printer' \",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"product\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The item that the customer wants to buy\"\n",
" },\n",
" },\n",
" \"required\": [\"product\"],\n",
" \"additionalProperties\": False\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "86f674a4-4b7c-443d-b025-0f016932508a",
"metadata": {},
"outputs": [],
"source": [
"# And this is included in a list of tools:\n",
"\n",
"tools = [{\"type\": \"function\", \"function\": price_function}]"
]
},
{
"cell_type": "markdown",
"id": "724d0f89-8a86-493e-8cd1-73814688a70b",
"metadata": {},
"source": [
"## Getting OpenAI to use our Tool\n",
"\n",
"There's some fiddly stuff to allow OpenAI \"to call our tool\"\n",
"\n",
"What we actually do is give the LLM the opportunity to inform us that it wants us to run the tool.\n",
"\n",
"Here's how the new chat function looks:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2d67fb72-132e-499e-9931-86cb71b634b6",
"metadata": {},
"outputs": [],
"source": [
"def chat(message, history):\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
"\n",
" if response.choices[0].finish_reason==\"tool_calls\":\n",
" message = response.choices[0].message\n",
" response, item = handle_tool_call(message)\n",
" print('response', response, 'item', item)\n",
" messages.append(message)\n",
" messages.append(response)\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
" \n",
" return response.choices[0].message.content"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3b4de767-954a-4077-a5f7-0055a0b90393",
"metadata": {},
"outputs": [],
"source": [
"# We have to write that function handle_tool_call:\n",
"\n",
"def handle_tool_call(message):\n",
" tool_call = message.tool_calls[0]\n",
" arguments = json.loads(tool_call.function.arguments)\n",
" item = arguments.get('product') \n",
" print('product', item)\n",
" price = get_item_price(item)\n",
" response = {\n",
" \"role\": \"tool\",\n",
" \"content\": json.dumps({\"item\": item,\"price\": price}),\n",
" \"tool_call_id\": tool_call.id\n",
" }\n",
" return response, item\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ffda702-6ac5-4d13-9703-a14fa93aea68",
"metadata": {},
"outputs": [],
"source": [
"gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ae2edbf-de58-43fa-b380-267cfc1755de",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading…
Cancel
Save