From the uDemy course on LLM engineering.
https://www.udemy.com/course/llm-engineering-master-ai-and-large-language-models
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
12 KiB
344 lines
12 KiB
{ |
|
"cells": [ |
|
{ |
|
"cell_type": "markdown", |
|
"id": "d006b2ea-9dfe-49c7-88a9-a5a0775185fd", |
|
"metadata": {}, |
|
"source": [ |
|
"# Additional End of week Exercise - week 2\n", |
|
"\n", |
|
"Now use everything you've learned from Week 2 to build a full prototype for the technical question/answerer you built in Week 1 Exercise.\n", |
|
"\n", |
|
"This should include a Gradio UI, streaming, use of the system prompt to add expertise, and the ability to switch between models. Bonus points if you can demonstrate use of a tool!\n", |
|
"\n", |
|
"If you feel bold, see if you can add audio input so you can talk to it, and have it respond with audio. ChatGPT or Claude can help you, or email me if you have questions.\n", |
|
"\n", |
|
"I will publish a full solution here soon - unless someone beats me to it...\n", |
|
"\n", |
|
"There are so many commercial applications for this, from a language tutor, to a company onboarding solution, to a companion AI to a course (like this one!) I can't wait to see your results." |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "a07e7793-b8f5-44f4-aded-5562f633271a", |
|
"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": "3ec1f21d-f043-43ca-8cdd-1f96328cf626", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"# Initialization\n", |
|
"\n", |
|
"load_dotenv()\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()" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "9eb2a0b7-771f-4140-9921-e7b2fb6829ae", |
|
"metadata": {}, |
|
"outputs": [], |
|
"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.\"" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "48ee97bf-f2ad-4ea3-b8a8-10686e56f9a6", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
" # Let's start by making a useful function -- tool function 1\n", |
|
"\n", |
|
"ticket_prices = {\"new york\": \"$999\", \"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\", \"new delhi\": \"$1111\"}\n", |
|
"\n", |
|
"def get_ticket_price(destination_city):\n", |
|
" print(f\"Tool get_ticket_price called for {destination_city}\")\n", |
|
" city = destination_city.lower()\n", |
|
" return ticket_prices.get(city, \"Unknown\")" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "20f1bae2-633b-4e69-accb-fcd99a452ea3", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"# There's a particular dictionary structure that's required to describe our tool function 1:\n", |
|
"\n", |
|
"price_function = {\n", |
|
" \"name\": \"get_ticket_price\",\n", |
|
" \"description\": \"Get the price of a return ticket to the destination city. Call this whenever you need to know the ticket price, for example when a customer asks 'How much is a ticket to this city'\",\n", |
|
" \"parameters\": {\n", |
|
" \"type\": \"object\",\n", |
|
" \"properties\": {\n", |
|
" \"destination_city\": {\n", |
|
" \"type\": \"string\",\n", |
|
" \"description\": \"The city that the customer wants to travel to\",\n", |
|
" },\n", |
|
" },\n", |
|
" \"required\": [\"destination_city\"],\n", |
|
" \"additionalProperties\": False\n", |
|
" }\n", |
|
"}" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "e0b28d2f-8f33-4627-99d6-7588d1d07077", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"#Assignment -- adding one more tool to book a flight -- tool function 2\n", |
|
"\n", |
|
"flight_booking_status = {\"new york\": \"blocked\", \"london\": \"booked\", \"paris\": \"can't be booked\", \"tokyo\": \"pending\", \"berlin\": \"payment issue\", \"new delhi\": \"cancelled\" }\n", |
|
"\n", |
|
"#this is a tool function that will be used by a GPT model\n", |
|
"\n", |
|
"def get_flight_booking_status(destination_city):\n", |
|
" print(f\"Tool get_flight_booking_status for {destination_city}\")\n", |
|
" city = destination_city.lower()\n", |
|
" return flight_booking_status.get(city, \"Unknown\")\n", |
|
" " |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "b5edcb58-06f6-47b9-8afd-25f786552862", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"# Describe metadata about the above tool function 2, so that model can understand it\n", |
|
"\n", |
|
"flight_booking_status_function = {\n", |
|
" \"name\": \"get_flight_booking_status\",\n", |
|
" \"description\": \"Book a flight and get its booking status. Show your answer in polite way, like flight booked, cancelled, pending or can't be booked etc...'\",\n", |
|
" \"parameters\": {\n", |
|
" \"type\": \"object\",\n", |
|
" \"properties\": {\n", |
|
" \"destination_city\": {\n", |
|
" \"type\": \"string\",\n", |
|
" \"description\": \"The city that the customer wants to book a flight for\",\n", |
|
" },\n", |
|
" },\n", |
|
" \"required\": [\"destination_city\"],\n", |
|
" \"additionalProperties\": False\n", |
|
" }\n", |
|
"}" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "c9bae64c-6f58-4eea-8db6-7117572f6ef3", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"# Some imports for handling images\n", |
|
"\n", |
|
"import base64\n", |
|
"from io import BytesIO\n", |
|
"from PIL import Image" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "6884b0db-2158-4bab-a492-56a8d7a20190", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"def artist(city):\n", |
|
" image_response = openai.images.generate(\n", |
|
" model=\"dall-e-3\",\n", |
|
" prompt=f\"An image representing a vacation in {city}, showing tourist spots and everything unique about {city}, in a vibrant pop-art style\",\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", |
|
" return Image.open(BytesIO(image_data))" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "64b3bc28-a45a-46d1-ab52-5c8868f68381", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"from pydub import AudioSegment\n", |
|
"from pydub.playback import play\n", |
|
"\n", |
|
"def talker(message):\n", |
|
" response = openai.audio.speech.create(\n", |
|
" model=\"tts-1\",\n", |
|
" voice=\"alloy\", # Also, try replacing onyx with alloy\n", |
|
" input=message\n", |
|
" )\n", |
|
" \n", |
|
" audio_stream = BytesIO(response.content)\n", |
|
" audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", |
|
" play(audio)" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "1eb4a6a2-2c69-4633-a51e-da6a6ee0e96b", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"#2 tools list - one to fetch the price, 2nd to fectch booking status\n", |
|
"tools = [{\"type\": \"function\", \"function\": price_function}, {\"type\": \"function\", \"function\": flight_booking_status_function}]" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "0f95bf11-0b05-424d-b721-f27551ef33f9", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"# We have to write a new function handle_multi_tool_calls to handle both the tools:\n", |
|
"\n", |
|
"def handle_multi_tool_calls(message):\n", |
|
" tool_call = message.tool_calls[0]\n", |
|
" arguments = json.loads(tool_call.function.arguments)\n", |
|
" city = arguments.get('destination_city')\n", |
|
" #get the ticket price\n", |
|
" price = get_ticket_price(city)\n", |
|
" #get the booking status\n", |
|
" booking_status = get_flight_booking_status(city)\n", |
|
" response = {\n", |
|
" \"role\": \"tool\",\n", |
|
" \"content\": json.dumps({\"destination_city\": city,\"price\": price, \"booking_status\": booking_status}),\n", |
|
" \"tool_call_id\": message.tool_calls[0].id\n", |
|
" }\n", |
|
" return response, city" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "b2b5f074-b19c-401b-bdf8-9414b2a81fd0", |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"#update the chat function to use both the tools\n", |
|
"def chat(history):\n", |
|
" messages = [{\"role\": \"system\", \"content\": system_message}] + history\n", |
|
" response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", |
|
" image = None\n", |
|
" \n", |
|
" if response.choices[0].finish_reason==\"tool_calls\":\n", |
|
" message = response.choices[0].message\n", |
|
" response, city = handle_multi_tool_calls(message)\n", |
|
" #set the city's image\n", |
|
" image = city\n", |
|
" messages.append(message)\n", |
|
" messages.append(response)\n", |
|
" image = artist(city)\n", |
|
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n", |
|
" \n", |
|
" reply = response.choices[0].message.content\n", |
|
" history += [{\"role\":\"assistant\", \"content\":reply}]\n", |
|
"\n", |
|
" # Comment out or delete the next line if you'd rather skip Audio for now..\n", |
|
" talker(reply)\n", |
|
" \n", |
|
" return history, image" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "9db28315-7aae-4a44-8711-73d12272e5e9", |
|
"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", |
|
"\n", |
|
"with gr.Blocks() as ui:\n", |
|
" with gr.Row():\n", |
|
" chatbot = gr.Chatbot(height=500, type=\"messages\")\n", |
|
" image_output = gr.Image(height=500)\n", |
|
" with gr.Row():\n", |
|
" entry = gr.Textbox(label=\"Chat with our AI Assistant:\")\n", |
|
" with gr.Row():\n", |
|
" clear = gr.Button(\"Clear\")\n", |
|
"\n", |
|
" def do_entry(message, history):\n", |
|
" history += [{\"role\":\"user\", \"content\":message}]\n", |
|
" return \"\", history\n", |
|
"\n", |
|
" entry.submit(do_entry, inputs=[entry, chatbot], outputs=[entry, chatbot]).then(\n", |
|
" chat, inputs=chatbot, outputs=[chatbot, image_output]\n", |
|
" )\n", |
|
" clear.click(lambda: None, inputs=None, outputs=chatbot, queue=False)\n", |
|
"\n", |
|
"ui.launch(inbrowser=True)" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"id": "873d3cda-2226-467a-a8c6-4a4ddd78c583", |
|
"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.10" |
|
} |
|
}, |
|
"nbformat": 4, |
|
"nbformat_minor": 5 |
|
}
|
|
|