|
|
@ -10,8 +10,8 @@ |
|
|
|
"- [x] get some extra **Python practice**\n", |
|
|
|
"- [x] get some extra **Python practice**\n", |
|
|
|
"- [x] get lots of **tool practice**\n", |
|
|
|
"- [x] get lots of **tool practice**\n", |
|
|
|
"- [x] increase your **Gradio proficiency**\n", |
|
|
|
"- [x] increase your **Gradio proficiency**\n", |
|
|
|
"- [ ] try **picture output** (on command only!)\n", |
|
|
|
"- [x] try **picture output** (on command only!)\n", |
|
|
|
"- [ ] try **audio 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", |
|
|
|
"- [ ] 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)_" |
|
|
|
"_Extra: delve into Claude's function calling documentation (can be left for later)_" |
|
|
|
] |
|
|
|
] |
|
|
@ -29,7 +29,11 @@ |
|
|
|
"from openai import OpenAI\n", |
|
|
|
"from openai import OpenAI\n", |
|
|
|
"import gradio as gr\n", |
|
|
|
"import gradio as gr\n", |
|
|
|
"import random\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": [ |
|
|
|
"source": [ |
|
|
|
"system_message = \"You are a helpful assistant for an Airline called FlightAI. \"\n", |
|
|
|
"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 += \"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", |
|
|
|
"\n", |
|
|
|
"def check_code(code):\n", |
|
|
|
"def check_code(code):\n", |
|
|
|
" valid = \"valid\" if re.match(\"^[0123456789BCDFXYZ]{2}[012346789HIJKLMNOPQRS]{2}[0123456789GHIJKLMNUOP]{2}$\", code) != None else \"not valid\"\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" |
|
|
|
" 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", |
|
|
|
"cell_type": "code", |
|
|
|
"execution_count": null, |
|
|
|
"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", |
|
|
|
"cell_type": "code", |
|
|
|
"execution_count": null, |
|
|
|
"execution_count": null, |
|
|
@ -194,7 +250,7 @@ |
|
|
|
"source": [ |
|
|
|
"source": [ |
|
|
|
"# List of tools:\n", |
|
|
|
"# List of tools:\n", |
|
|
|
"\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", |
|
|
|
" \n", |
|
|
|
" if response.choices[0].finish_reason==\"tool_calls\":\n", |
|
|
|
" if response.choices[0].finish_reason==\"tool_calls\":\n", |
|
|
|
" message = response.choices[0].message\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", |
|
|
|
" messages.append(message)\n", |
|
|
|
" for response in responses:\n", |
|
|
|
" for response in responses:\n", |
|
|
|
" messages.append(response)\n", |
|
|
|
" messages.append(response)\n", |
|
|
|
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n", |
|
|
|
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n", |
|
|
|
" \n", |
|
|
|
" \n", |
|
|
|
" reply = response.choices[0].message.content\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", |
|
|
|
" history += [{\"role\": \"assistant\", \"content\": reply}]\n", |
|
|
|
" \n", |
|
|
|
" \n", |
|
|
|
" return history, image" |
|
|
|
" return history, image" |
|
|
@ -232,6 +292,8 @@ |
|
|
|
"source": [ |
|
|
|
"source": [ |
|
|
|
"def handle_tool_call(message):\n", |
|
|
|
"def handle_tool_call(message):\n", |
|
|
|
" responses = []\n", |
|
|
|
" responses = []\n", |
|
|
|
|
|
|
|
" image = None\n", |
|
|
|
|
|
|
|
" \n", |
|
|
|
" for tool_call in message.tool_calls:\n", |
|
|
|
" for tool_call in message.tool_calls:\n", |
|
|
|
" arguments = json.loads(tool_call.function.arguments)\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", |
|
|
|
" 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", |
|
|
|
" outdata = get_ticket_price(indata)\n", |
|
|
|
" input_name = \"destination city\"\n", |
|
|
|
" input_name = \"destination city\"\n", |
|
|
|
" output_name = \"price\"\n", |
|
|
|
" output_name = \"price\"\n", |
|
|
|
" elif function_name == 'book_travel':\n", |
|
|
|
" elif function_name == 'book_flight':\n", |
|
|
|
" outdata = book_flight(indata)\n", |
|
|
|
" outdata = book_flight(indata)\n", |
|
|
|
" input_name = \"destination city\"\n", |
|
|
|
" input_name = \"destination city\"\n", |
|
|
|
" output_name = \"booking code\"\n", |
|
|
|
" output_name = \"booking code\"\n", |
|
|
|
" else:\n", |
|
|
|
" elif function_name == \"check_code\":\n", |
|
|
|
" outdata = check_code(indata)\n", |
|
|
|
" outdata = check_code(indata)\n", |
|
|
|
" input_name = \"booking code\"\n", |
|
|
|
" input_name = \"booking code\"\n", |
|
|
|
" output_name = \"validity\"\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", |
|
|
|
" responses.append({\n", |
|
|
|
" \"role\": \"tool\",\n", |
|
|
|
" \"role\": \"tool\",\n", |
|
|
|
" \"content\": json.dumps({input_name: indata, output_name: outdata}),\n", |
|
|
|
" \"content\": json.dumps({input_name: indata, output_name: outdata}),\n", |
|
|
|
" \"tool_call_id\": tool_call.id\n", |
|
|
|
" \"tool_call_id\": tool_call.id\n", |
|
|
|
" })\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": {}, |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"source": [ |
|
|
|
"# More involved Gradio code as we're not using the preset Chat interface!\n", |
|
|
|
"## Gradio\n", |
|
|
|
"# Passing in inbrowser=True in the last line will cause a Gradio window to pop up immediately.\n", |
|
|
|
|
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"with gr.Blocks() as ui:\n", |
|
|
|
"with gr.Blocks() as ui:\n", |
|
|
|
" with gr.Row():\n", |
|
|
|
" with gr.Row():\n", |
|
|
|