From c3e92f97208b053f9cd4550b8ff1981fbd6232af Mon Sep 17 00:00:00 2001 From: udomai Date: Sat, 15 Feb 2025 20:46:48 +0100 Subject: [PATCH] update udo's main branch --- .gitignore | 3 + udo/w1d1/beautifulSoupOnly.ipynb | 2 +- udo/w2d5/TravelAgent.ipynb | 115 +++++++++++++++++++++++++++---- 3 files changed, 106 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 053b56b..24fe978 100644 --- a/.gitignore +++ b/.gitignore @@ -182,3 +182,6 @@ products_vectorstore/ # ignore optimized C++ code from being checked into repo week4/optimized week4/simple + +# ignore my stuff +udo diff --git a/udo/w1d1/beautifulSoupOnly.ipynb b/udo/w1d1/beautifulSoupOnly.ipynb index 30671d3..8cee291 100644 --- a/udo/w1d1/beautifulSoupOnly.ipynb +++ b/udo/w1d1/beautifulSoupOnly.ipynb @@ -66,7 +66,7 @@ "outputs": [], "source": [ "if(result == normal):\n", - " print(\"No change.\")\n", + " print(\"No change, but stay hopeful! It won't be much longer.\")\n", "else:\n", " print(\"CHECK THE WEBSITE NOW!\")" ] diff --git a/udo/w2d5/TravelAgent.ipynb b/udo/w2d5/TravelAgent.ipynb index 2191bc9..2d5715a 100644 --- a/udo/w2d5/TravelAgent.ipynb +++ b/udo/w2d5/TravelAgent.ipynb @@ -10,8 +10,8 @@ "- [x] get some extra **Python practice**\n", "- [x] get lots of **tool practice**\n", "- [x] increase your **Gradio proficiency**\n", - "- [ ] try **picture output** (on command only!)\n", - "- [ ] try **audio output** (on command only?)\n", + "- [x] try **picture output** (on command only!)\n", + "- [x] try **audio output** (on command only?)\n", "- [ ] try **audio input?** (most importantly, do anything you saw in the video; the rest is nice-to-have)\n", "_Extra: delve into Claude's function calling documentation (can be left for later)_" ] @@ -29,7 +29,11 @@ "from openai import OpenAI\n", "import gradio as gr\n", "import random\n", - "import re" + "import re\n", + "import base64\n", + "from io import BytesIO\n", + "from PIL import Image\n", + "from IPython.display import Audio, display" ] }, { @@ -60,7 +64,9 @@ "source": [ "system_message = \"You are a helpful assistant for an Airline called FlightAI. \"\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. \"" + "system_message += \"Always be accurate. If you don't know the answer, say so. \"\n", + "system_message += \"You can book flights directly. \"\n", + "system_message += \"You can generate beautiful artistic renditions of the cities we fly to.\"" ] }, { @@ -107,10 +113,36 @@ "\n", "def check_code(code):\n", " valid = \"valid\" if re.match(\"^[0123456789BCDFXYZ]{2}[012346789HIJKLMNOPQRS]{2}[0123456789GHIJKLMNUOP]{2}$\", code) != None else \"not valid\"\n", - " println(f\"Code checker called for code {code}, which is {valid}.\")\n", + " print(f\"Code checker called for code {code}, which is {valid}.\")\n", " return re.match(\"^[0123456789BCDFXYZ]{2}[012346789HIJKLMNOPQRS]{2}[0123456789GHIJKLMNUOP]{2}$\", code) != None" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1d1b1c2-089c-41e5-b1bd-900632271093", + "metadata": {}, + "outputs": [], + "source": [ + "# make a nice preview of the travel destination\n", + "\n", + "def artist(city):\n", + " image_response = openai.images.generate(\n", + " model=\"dall-e-3\",\n", + " prompt=f\"Make an image in the style of a vibrant, artistically filtered photo that is a collage of the best sights and views in {city}.\",\n", + " size=\"1024x1024\",\n", + " n=1,\n", + " response_format=\"b64_json\",\n", + " )\n", + " image_base64 = image_response.data[0].b64_json\n", + " image_data = base64.b64decode(image_base64)\n", + " img = Image.open(BytesIO(image_data))\n", + "\n", + " img.save(\"img001.png\") #make them 4 cents count! .save is from PIL library, btw\n", + " \n", + " return img" + ] + }, { "cell_type": "code", "execution_count": null, @@ -160,6 +192,30 @@ "}" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc365d87-fed2-41ff-9232-850fdce1cff2", + "metadata": {}, + "outputs": [], + "source": [ + "artist_function = {\n", + " \"name\": \"artist\",\n", + " \"description\": \"Call this whenever you need to generate a picture, photo, or graphic impression of a city.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city of which an image is to be generated\",\n", + " },\n", + " },\n", + " \"required\": [\"city\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}" + ] + }, { "cell_type": "code", "execution_count": null, @@ -194,7 +250,7 @@ "source": [ "# List of tools:\n", "\n", - "tools = [{\"type\": \"function\", \"function\": price_function}, {\"type\": \"function\", \"function\": booking_function}, {\"type\": \"function\", \"function\": codecheck_function}]" + "tools = [{\"type\": \"function\", \"function\": price_function}, {\"type\": \"function\", \"function\": booking_function}, {\"type\": \"function\", \"function\": codecheck_function}, {\"type\": \"function\", \"function\": artist_function}]" ] }, { @@ -211,13 +267,17 @@ " \n", " if response.choices[0].finish_reason==\"tool_calls\":\n", " message = response.choices[0].message\n", - " responses = handle_tool_call(message)\n", + " responses = handle_tool_call(message)[0]\n", + " image = handle_tool_call(message)[1]\n", " messages.append(message)\n", " for response in responses:\n", " messages.append(response)\n", " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", " \n", " reply = response.choices[0].message.content\n", + "\n", + " #talker(reply) #current cost: $0.015 per 1000 characters (not tokens!)\n", + " \n", " history += [{\"role\": \"assistant\", \"content\": reply}]\n", " \n", " return history, image" @@ -232,6 +292,8 @@ "source": [ "def handle_tool_call(message):\n", " responses = []\n", + " image = None\n", + " \n", " for tool_call in message.tool_calls:\n", " arguments = json.loads(tool_call.function.arguments)\n", " indata = arguments[list(arguments.keys())[0]] # works for now because we only have one argument in each of our functions\n", @@ -240,21 +302,49 @@ " outdata = get_ticket_price(indata)\n", " input_name = \"destination city\"\n", " output_name = \"price\"\n", - " elif function_name == 'book_travel':\n", + " elif function_name == 'book_flight':\n", " outdata = book_flight(indata)\n", " input_name = \"destination city\"\n", " output_name = \"booking code\"\n", - " else:\n", + " elif function_name == \"check_code\":\n", " outdata = check_code(indata)\n", " input_name = \"booking code\"\n", " output_name = \"validity\"\n", - " \n", + " elif function_name == \"artist\":\n", + " image = artist(indata)\n", + " outdata = f\"artistic rendition of {indata}\"\n", + " input_name = \"city\"\n", + " output_name = \"image\"\n", + "\n", " responses.append({\n", " \"role\": \"tool\",\n", " \"content\": json.dumps({input_name: indata, output_name: outdata}),\n", " \"tool_call_id\": tool_call.id\n", " })\n", - " return responses" + "\n", + " return responses, image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "505b585e-e9f9-4326-8455-184398bc82d1", + "metadata": {}, + "outputs": [], + "source": [ + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\",\n", + " input=message)\n", + "\n", + " audio_stream = BytesIO(response.content)\n", + " output_filename = \"output_audio.mp3\"\n", + " with open(output_filename, \"wb\") as f:\n", + " f.write(audio_stream.read())\n", + "\n", + " # Play the generated audio\n", + " display(Audio(output_filename, autoplay=True))" ] }, { @@ -264,8 +354,7 @@ "metadata": {}, "outputs": [], "source": [ - "# More involved Gradio code as we're not using the preset Chat interface!\n", - "# Passing in inbrowser=True in the last line will cause a Gradio window to pop up immediately.\n", + "## Gradio\n", "\n", "with gr.Blocks() as ui:\n", " with gr.Row():\n",