diff --git a/week1/week1 EXERCISE.ipynb b/week1/week1 EXERCISE.ipynb deleted file mode 100644 index f3486fe..0000000 --- a/week1/week1 EXERCISE.ipynb +++ /dev/null @@ -1,104 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "fe12c203-e6a6-452c-a655-afb8a03a4ff5", - "metadata": {}, - "source": [ - "# End of week 1 exercise\n", - "\n", - "To demonstrate your familiarity with OpenAI API, and also Ollama, build a tool that takes a technical question, \n", - "and responds with an explanation. This is a tool that you will be able to use yourself during the course!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c1070317-3ed9-4659-abe3-828943230e03", - "metadata": {}, - "outputs": [], - "source": [ - "# imports" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4a456906-915a-4bfd-bb9d-57e505c5093f", - "metadata": {}, - "outputs": [], - "source": [ - "# constants\n", - "\n", - "MODEL_GPT = 'gpt-4o-mini'\n", - "MODEL_LLAMA = 'llama3.2'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8d7923c-5f28-4c30-8556-342d7c8497c1", - "metadata": {}, - "outputs": [], - "source": [ - "# set up environment" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3f0d0137-52b0-47a8-81a8-11a90a010798", - "metadata": {}, - "outputs": [], - "source": [ - "# here is the question; type over this to ask something new\n", - "\n", - "question = \"\"\"\n", - "Please explain what this code does and why:\n", - "yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "60ce7000-a4a5-4cce-a261-e75ef45063b4", - "metadata": {}, - "outputs": [], - "source": [ - "# Get gpt-4o-mini to answer, with streaming" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8f7c8ea8-4082-4ad0-8751-3301adcf6538", - "metadata": {}, - "outputs": [], - "source": [ - "# Get Llama 3.2 to answer" - ] - } - ], - "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 -} diff --git a/week2/community-contributions/day4-industrial-tools-info.ipynb b/week2/community-contributions/day4-industrial-tools-info.ipynb new file mode 100644 index 0000000..e828b8b --- /dev/null +++ b/week2/community-contributions/day4-industrial-tools-info.ipynb @@ -0,0 +1,416 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "d98f69c3-9b4b-4e23-a56b-a7433b853548", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import json\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr\n", + "import random\n", + "import string\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 with sk-proj\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + "\n", + "MODEL = \"gpt-4o-mini\"\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ee617ed-cc41-4bb0-a3e2-03e45b9a5cca", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = (\n", + " \"You are a helpful assistant for an e-commerce company called SparksAI.\\n\\n\"\n", + " \"When the user wants to buy a product, follow these steps:\\n\"\n", + " \"1. Ask for the name of the product.\\n\"\n", + " \"2. Ask for the quantity they want.\\n\"\n", + " \"3. Call the function 'check_product_availability' with the name of the product the user wants to buy.\\n\"\n", + " \" - If it returns an empty list, say: 'Product not available'.\\n\"\n", + " \" - If it returns products, list them EXACTLY, in a numbered list, showing name, quantity and price.\\n\"\n", + " \"4. Ask the customer if they want something else. If yes then repeat steps 1 to 3.\\n\"\n", + " \"5. Wait for the user to confirm the selection.\\n\"\n", + " \"6. Then ask for customer's first name, last name, and email.\\n\"\n", + " \"7. Ask for the complete delivery address in the following format.\\n\"\n", + " \" - Address Line 1 \\n\"\n", + " \" - Suite No., Apt No., Building No. (optional)\\n\"\n", + " \" - Zip Code\\n\"\n", + " \" - Phone number\\n\"\n", + " \"6. Finally call 'order_product' to confirm and show the user the real order details with the generated order number and all the details of the product that they ordered along with the total amount that they have to pay.\\n\"\n", + " \"- Always call 'check_product_availability' if user mentions a new product.\\n\"\n", + " \"- Do not invent products. Use what the function calls return.\\n\"\n", + " \"- If a product is not available, say 'Product not found'.\\n\"\n", + " \"If you don't know something, say so.\\n\"\n", + " \"Keep answers precise and professional.\\n\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "050e7a80-da02-4319-84cc-2ddf54a83f11", + "metadata": {}, + "outputs": [], + "source": [ + "available_products = {\n", + " \"fevicol\": [\n", + " {\n", + " \"name\": \"Fevicol PL 333\",\n", + " \"quantity\": \"5 litres\",\n", + " \"price\": \"$20\"\n", + " },\n", + " {\n", + " \"name\": \"Fevicol PL 111\",\n", + " \"quantity\": \"5 litres\",\n", + " \"price\": \"$25\"\n", + " },\n", + " {\n", + " \"name\": \"Fevicol SR 505\",\n", + " \"quantity\": \"5 litres\",\n", + " \"price\": \"$30\"\n", + " },\n", + " ],\n", + " \"loctite\": [\n", + " {\n", + " \"name\": \"Loctite 401\",\n", + " \"quantity\": \"50 ml\",\n", + " \"price\": \"$25\"\n", + " },\n", + " {\n", + " \"name\": \"Loctite 243\",\n", + " \"quantity\": \"250 ml\",\n", + " \"price\": \"$40\"\n", + " },\n", + " {\n", + " \"name\": \"Loctite 638\",\n", + " \"quantity\": \"50 ml\",\n", + " \"price\": \"$30\"\n", + " }\n", + " ],\n", + " \"3m\": [\n", + " {\n", + " \"name\": \"3M Scotch-Weld 2216\",\n", + " \"quantity\": \"200 ml\",\n", + " \"price\": \"$50\"\n", + " },\n", + " {\n", + " \"name\": \"3M Super 77\",\n", + " \"quantity\": \"500 ml\",\n", + " \"price\": \"$35\"\n", + " },\n", + " {\n", + " \"name\": \"3M Fastbond 30\",\n", + " \"quantity\": \"1 gallon\",\n", + " \"price\": \"$80\"\n", + " }\n", + " ],\n", + " \"bosch\": [\n", + " {\n", + " \"name\": \"Bosch PU Adhesive\",\n", + " \"quantity\": \"1 litre\",\n", + " \"price\": \"$28\"\n", + " },\n", + " {\n", + " \"name\": \"Bosch Epoxy Resin\",\n", + " \"quantity\": \"500 ml\",\n", + " \"price\": \"$18\"\n", + " },\n", + " {\n", + " \"name\": \"Bosch High-Strength Glue\",\n", + " \"quantity\": \"750 ml\",\n", + " \"price\": \"$22\"\n", + " }\n", + " ],\n", + " \"araldite\": [\n", + " {\n", + " \"name\": \"Araldite Standard Epoxy\",\n", + " \"quantity\": \"500 gm\",\n", + " \"price\": \"$20\"\n", + " },\n", + " {\n", + " \"name\": \"Araldite Rapid Adhesive\",\n", + " \"quantity\": \"1 litre\",\n", + " \"price\": \"$35\"\n", + " },\n", + " {\n", + " \"name\": \"Araldite Super Strength\",\n", + " \"quantity\": \"250 ml\",\n", + " \"price\": \"$15\"\n", + " }\n", + " ]\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c379a9f6-2692-412a-9d5b-b9a11b5914d1", + "metadata": {}, + "outputs": [], + "source": [ + "def generate_order_number(prefix=\"SPK\", length=8):\n", + " random_part = ''.join(random.choices(string.ascii_uppercase + string.digits, k=length))\n", + " return f\"{prefix}-{random_part}\"\n", + "\n", + "def check_product_availability(product_name: str):\n", + " print(f\"[TOOL] check_product_availability({product_name})\")\n", + " product = product_name.lower()\n", + " return available_products.get(product, [])\n", + "\n", + "def order_product(order_details):\n", + " print(f\"Order confirmed! Your order number is {order_details['order_number']}.\")\n", + " print(\"Order details:\")\n", + " for item in order_details[\"products\"]:\n", + " print(f\"- {item['name']} x{item['quantity']} - ${item['price']}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c29fb56c-4177-4cdd-8f28-e84b42dd8225", + "metadata": {}, + "outputs": [], + "source": [ + "tools = [\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"check_product_availability\",\n", + " \"description\": \"Checks if a product is available in inventory.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"product_name\": {\"type\": \"string\", \"description\": \"Name of the product to check.\"}\n", + " },\n", + " \"required\": [\"product_name\"]\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"order_product\",\n", + " \"description\": \"Places an order for a product.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"order_number\": {\"type\": \"string\", \"description\": \"Unique order number.\"},\n", + " \"customer\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"first_name\": {\"type\": \"string\"},\n", + " \"last_name\": {\"type\": \"string\"},\n", + " \"email\": {\"type\": \"string\"}\n", + " },\n", + " \"required\": [\"first_name\", \"last_name\", \"email\"]\n", + " },\n", + " \"delivery_address\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"address_line1\": {\"type\": \"string\"},\n", + " \"address_line2\": {\"type\": \"string\"},\n", + " \"zip_code\": {\"type\": \"string\"},\n", + " \"phone_number\": {\"type\": \"string\"}\n", + " },\n", + " \"required\": [\"address_line1\", \"zip_code\", \"phone_number\"]\n", + " },\n", + " \"products\": {\n", + " \"type\": \"array\",\n", + " \"items\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"name\": {\"type\": \"string\"},\n", + " \"quantity\": {\"type\": \"integer\"},\n", + " \"price\": {\"type\": \"number\"}\n", + " },\n", + " \"required\": [\"name\", \"quantity\", \"price\"]\n", + " }\n", + " }\n", + " },\n", + " \"required\": [\"order_number\", \"customer\", \"delivery_address\", \"products\"]\n", + " }\n", + " }\n", + " }\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51b8a50a-fd97-4fb2-b015-2d16dc0443d6", + "metadata": {}, + "outputs": [], + "source": [ + "def handle_tool_call(tool_call):\n", + " \"\"\"\n", + " Handles a single function call requested by the LLM.\n", + " \"\"\"\n", + " fn_name = tool_call.function.name # Use dot notation\n", + " args = json.loads(tool_call.function.arguments) # Convert JSON string to dictionary\n", + "\n", + " if fn_name == \"check_product_availability\":\n", + " product_name = args.get(\"product_name\")\n", + " available_products = check_product_availability(product_name) # Ensure this function exists\n", + " response_content = {\"product_name\": product_name, \"availability\": available_products}\n", + "\n", + " elif fn_name == \"order_product\":\n", + " customer = args.get(\"customer\")\n", + " address = args.get(\"delivery_address\")\n", + " products = args.get(\"products\")\n", + " order_number = generate_order_number()\n", + "\n", + " order_details = {\n", + " \"order_number\": order_number,\n", + " \"customer\": customer,\n", + " \"delivery_address\": address,\n", + " \"products\": products\n", + " }\n", + "\n", + " order_product(order_details) # Ensure this function exists\n", + " response_content = {\"order_number\": order_number, \"order_details\": order_details}\n", + "\n", + " elif fn_name == \"generate_order_number\":\n", + " prefix = args.get(\"prefix\", \"SPK\")\n", + " length = args.get(\"length\", 8)\n", + " order_number = generate_order_number(prefix, length)\n", + " response_content = {\"order_number\": order_number}\n", + "\n", + " else:\n", + " response_content = {\"error\": f\"Unknown function: {fn_name}\"}\n", + "\n", + " return {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps(response_content),\n", + " \"tool_call_id\": tool_call.id, # Use dot notation\n", + " }, args" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f94ce1bc-db96-485b-bce2-980573a5956f", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message, history):\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 # Ensure this is a correctly defined list of tools\n", + " )\n", + "\n", + " # Check if OpenAI wants to call a tool\n", + " while response.choices[0].finish_reason == \"tool_calls\":\n", + " msg = response.choices[0].message # This is a ChatCompletionMessage object\n", + "\n", + " print(\"[DEBUG] msg.tool_calls:\", msg.tool_calls)\n", + "\n", + " if isinstance(msg.tool_calls, list) and msg.tool_calls:\n", + " print(\"[DEBUG] First tool call:\", msg.tool_calls[0])\n", + " else:\n", + " print(\"[ERROR] No valid tool call found\")\n", + "\n", + " tool_call = msg.tool_calls[0] # Extract the tool call object\n", + "\n", + " print(f\"[INFO] Tool call requested: {tool_call}\")\n", + "\n", + " # Extract function name and arguments safely\n", + " fn_name = tool_call.function.name\n", + " fn_args = json.loads(tool_call.function.arguments) # Convert JSON string to dictionary\n", + "\n", + " # Handle the tool call\n", + " tool_response, tool_args = handle_tool_call(tool_call)\n", + "\n", + " print(f\"[INFO] Tool response: {tool_response}\")\n", + "\n", + " messages.append({\n", + " \"role\": \"assistant\",\n", + " \"content\": None,\n", + " \"tool_calls\": [{\n", + " \"id\": tool_call.id,\n", + " \"type\": \"function\", # Required field\n", + " \"function\": {\n", + " \"name\": tool_call.function.name,\n", + " \"arguments\": json.dumps(fn_args) # Ensure this is a valid JSON string\n", + " }\n", + " }]\n", + " })\n", + "\n", + " messages.append({\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps(tool_response),\n", + " \"tool_call_id\": tool_call.id\n", + " })\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", + " tools=tools\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.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbabad4d-48bc-4561-b49a-f86446514059", + "metadata": {}, + "outputs": [], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17d03094-713b-4ece-84c7-d2042dcbd263", + "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 +}