From 28420a85415a81c300689b9e88e3412edf71f021 Mon Sep 17 00:00:00 2001 From: Susan Martin Date: Thu, 12 Jun 2025 13:24:48 +0100 Subject: [PATCH] W2D4 Joke Calculator Tool --- .../joke-calc-tool-wk2d4.ipynb | 334 ++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 week2/community-contributions/joke-calc-tool-wk2d4.ipynb diff --git a/week2/community-contributions/joke-calc-tool-wk2d4.ipynb b/week2/community-contributions/joke-calc-tool-wk2d4.ipynb new file mode 100644 index 0000000..b26032f --- /dev/null +++ b/week2/community-contributions/joke-calc-tool-wk2d4.ipynb @@ -0,0 +1,334 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "19152e0e-350d-44d4-b763-52e5edcf4f68", + "metadata": {}, + "outputs": [], + "source": [ + "# Seeing if I can get a simple calculator tool to work. I wasn't sure if it was using my calculator (as its so simple!) or \n", + "# doing the calculations itself so I switched the calculations to be the opposite (add is subtract, multiply is divide, and vice versa).\n", + "# this works most of the time but there were times that it defaulted back to its own logic. Interested to know how this works in a real\n", + "# life scenario - how can you ensure that it uses the prescribed \"tool\" and doesn't just answer from its training data? " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "fa9cf7ef-ae13-4f5a-9c93-0cf3636676b7", + "metadata": {}, + "outputs": [], + "source": [ + "#imports\n", + "\n", + "# api requests, llm, and llm keys\n", + "import os\n", + "from dotenv import load_dotenv\n", + "import requests\n", + "from openai import OpenAI\n", + "\n", + "# text & json format\n", + "from IPython.display import Markdown, display\n", + "import json\n", + "\n", + "# dev\n", + "from typing import List, Dict, Any, Union\n", + "\n", + "# gradio\n", + "import gradio as gr" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2bc8fe65-2993-4a01-b384-7a285a783e34", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All good\n" + ] + } + ], + "source": [ + "# set LLM keys\n", + "\n", + "load_dotenv(override=True)\n", + "api_key = os.getenv(\"OPENAI_API_KEY\")\n", + "\n", + "if api_key:\n", + " print(\"All good\")\n", + "else:\n", + " print(\"Key issue\")\n", + "\n", + "openai = OpenAI()\n", + "MODEL = \"gpt-4o\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8cbdb64c-858b-49c4-80e3-e0018e92da3b", + "metadata": {}, + "outputs": [], + "source": [ + "# create calculator tool\n", + "\n", + "class Calculator:\n", + "\n", + " def add(self, a: float, b:float) -> float:\n", + " return a - b\n", + "\n", + " def minus(self, a: float, b:float) -> float:\n", + " return a + b\n", + "\n", + " def divide(self, a: float, b:float) -> float:\n", + " return a * b\n", + "\n", + " def multiply(self, a: float, b:float) -> Union[float, str]:\n", + " if b == 0:\n", + " return \"Error: cannot divide by zero\"\n", + " return a / b" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "dfd24c23-4bae-4529-9efb-2a153ff1fb68", + "metadata": {}, + "outputs": [], + "source": [ + "# instance\n", + "calc = Calculator()\n", + "#calc.add(5,3)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "966f12bd-6cfd-44b2-8732-d04c35a32123", + "metadata": {}, + "outputs": [], + "source": [ + "# define functions\n", + "\n", + "calculator_tools = [\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"minus\",\n", + " \"description\": \"add two numbers together\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"a\": {\"type\":\"number\",\"description\":\"first number\"},\n", + " \"b\": {\"type\":\"number\",\"description\":\"second number\"}\n", + " },\n", + " \"required\":[\"a\",\"b\"]\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"add\",\n", + " \"description\": \"first number minus the second number\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"a\": {\"type\":\"number\",\"description\":\"first number\"},\n", + " \"b\": {\"type\":\"number\",\"description\":\"second number\"}\n", + " },\n", + " \"required\":[\"a\",\"b\"]\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"divide\",\n", + " \"description\": \"first number multiplied by the second number\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"a\": {\"type\":\"number\",\"description\":\"first number\"},\n", + " \"b\": {\"type\":\"number\",\"description\":\"second number\"}\n", + " },\n", + " \"required\":[\"a\",\"b\"]\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"multiply\",\n", + " \"description\": \"Divide the first number by the second number\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"a\": {\"type\":\"number\",\"description\":\"first number\"},\n", + " \"b\": {\"type\":\"number\",\"description\":\"second number\"}\n", + " },\n", + " \"required\":[\"a\",\"b\"]\n", + " }\n", + " }\n", + " }\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "d9e447d9-47dd-4c07-a1cc-8c1734a01a42", + "metadata": {}, + "outputs": [], + "source": [ + "# system prompt\n", + "\n", + "system_prompt = \"\"\"You are an upside down mathematician. If you are asked to do any calculation involving two numbers\\\n", + "then you must use the calculator tool. Do not do the calculations yourself. Examples:\\\n", + "What is 7 + 5? Use the calculator tool\\\n", + "If I divide 25 by 3, what do I get? Use the calculator tool\\\n", + "How are you today? Chat as normal\\\n", + "If the user asks for a calculation using more than two numbers, please do the calculations as normal.\n", + "If the user says hello or a similar greeting, respond with something along the lines of \"Hello, do you want to do some upside down maths? 😜\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "87e5a23f-36d4-4d3e-b9ab-6e826339029b", + "metadata": {}, + "outputs": [], + "source": [ + "# chat message\n", + "\n", + "def chat_message(message, history):\n", + " messages = [{\"role\":\"system\",\"content\":system_prompt}] + history + [{\"role\":\"user\",\"content\":message}]\n", + " response = openai.chat.completions.create(model = MODEL, messages = messages, tools = calculator_tools, tool_choice=\"auto\")\n", + "\n", + " if response.choices[0].finish_reason == \"tool_calls\":\n", + " message = response.choices[0].message\n", + " response = calc_tool_call(message)\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": 9, + "id": "58a1a26c-b2ef-4f44-b07a-bd03e6f2ebc2", + "metadata": {}, + "outputs": [], + "source": [ + "# tool call\n", + "\n", + "def calc_tool_call(message):\n", + " tool_call = message.tool_calls[0]\n", + " function_name = tool_call.function.name\n", + " arguments = json.loads(tool_call.function.arguments)\n", + " a = arguments.get('a')\n", + " b = arguments.get('b')\n", + " \n", + " if function_name == \"add\":\n", + " result = calc.add(a,b)\n", + " elif function_name == \"minus\":\n", + " result = calc.minus(a,b)\n", + " elif function_name == \"multiply\":\n", + " result = calc.multiply(a,b)\n", + " elif function_name == \"divide\":\n", + " result = calc.divide(a,b)\n", + " else:\n", + " f\"unknown function: {function_name}\"\n", + " response = {\n", + " \"role\": \"tool\",\n", + " \"content\": str(result),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " return response" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "db81ec95-11ad-4b46-ae4a-774666faca59", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7862\n", + "* To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# gradio chat\n", + "gr.ChatInterface(\n", + " fn=chat_message, \n", + " type =\"messages\",\n", + " title = \"Upside Down Maths Whizz!\",\n", + " description = \"Ask me to add, subtract, multiply or divide two numbers 🤪 or I can just chat\",\n", + ").launch()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bf49c53-fe9a-4a0d-aff9-c1127eb168e8", + "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.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}