1 changed files with 0 additions and 355 deletions
@ -1,355 +0,0 @@ |
|||||||
{ |
|
||||||
"cells": [ |
|
||||||
{ |
|
||||||
"cell_type": "markdown", |
|
||||||
"id": "ddfa9ae6-69fe-444a-b994-8c4c5970a7ec", |
|
||||||
"metadata": {}, |
|
||||||
"source": [ |
|
||||||
"# Project - Airline AI Assistant\n", |
|
||||||
"\n", |
|
||||||
"We'll now bring together what we've learned to make an AI Customer Support assistant for an Airline" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "8b50bbe2-c0b1-49c3-9a5c-1ba7efa2bcb4", |
|
||||||
"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": "747e8786-9da8-4342-b6c9-f5f69c2e22ae", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# Initialization\n", |
|
||||||
"\n", |
|
||||||
"load_dotenv(override=True)\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()\n", |
|
||||||
"\n", |
|
||||||
"# As an alternative, if you'd like to use Ollama instead of OpenAI\n", |
|
||||||
"# Check that Ollama is running for you locally (see week1/day2 exercise) then uncomment these next 2 lines\n", |
|
||||||
"# MODEL = \"llama3.2\"\n", |
|
||||||
"# openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "0a521d84-d07c-49ab-a0df-d6451499ed97", |
|
||||||
"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": "61a2a15d-b559-4844-b377-6bd5cb4949f6", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n", |
|
||||||
"\n", |
|
||||||
"def chat(message, history):\n", |
|
||||||
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", |
|
||||||
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n", |
|
||||||
" return response.choices[0].message.content\n", |
|
||||||
"\n", |
|
||||||
"gr.ChatInterface(fn=chat, type=\"messages\").launch()" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "markdown", |
|
||||||
"id": "36bedabf-a0a7-4985-ad8e-07ed6a55a3a4", |
|
||||||
"metadata": {}, |
|
||||||
"source": [ |
|
||||||
"## Tools\n", |
|
||||||
"\n", |
|
||||||
"Tools are an incredibly powerful feature provided by the frontier LLMs.\n", |
|
||||||
"\n", |
|
||||||
"With tools, you can write a function, and have the LLM call that function as part of its response.\n", |
|
||||||
"\n", |
|
||||||
"Sounds almost spooky.. we're giving it the power to run code on our machine?\n", |
|
||||||
"\n", |
|
||||||
"Well, kinda." |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "0696acb1-0b05-4dc2-80d5-771be04f1fb2", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# Let's start by making a useful function\n", |
|
||||||
"\n", |
|
||||||
"ticket_prices = {\"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\"}\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": "80ca4e09-6287-4d3f-997d-fa6afbcf6c85", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"get_ticket_price(\"Berlin\")" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "4afceded-7178-4c05-8fa6-9f2085e6a344", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# There's a particular dictionary structure that's required to describe our function:\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": "b6c73b6b-1f9f-4df3-bd36-f6c8bf45a670", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"from datetime import date, datetime\n", |
|
||||||
"\n", |
|
||||||
"availabilities = {\"london\": \"01/01/2025-31/03/2025\", \"paris\": \"01/01/2025-31/12/2025\", \"tokyo\": \"05/06/2024-04/06/2025\", \"berlin\": \"01/12/2024-30/09/2025\"}\n", |
|
||||||
"\n", |
|
||||||
"def get_availability_period(destination_city, flight_date):\n", |
|
||||||
" \"\"\"Check for dates as LLM answers on this are not reliable.\"\"\"\n", |
|
||||||
" print(f\"Tool get_availability_period called for {destination_city}\")\n", |
|
||||||
" \n", |
|
||||||
" city = destination_city.lower()\n", |
|
||||||
" availability = availabilities.get(city)\n", |
|
||||||
" \n", |
|
||||||
" if availability:\n", |
|
||||||
" current_date = date.today()\n", |
|
||||||
" if len(flight_date.split(\"-\")) == 2:\n", |
|
||||||
" flight_date = f\"{flight_date}-{str(current_date.year)}\"\n", |
|
||||||
" flight_date = datetime.strptime(flight_date, \"%d-%m-%Y\").date()\n", |
|
||||||
" \n", |
|
||||||
" start_str, end_str = availability.split(\"-\")\n", |
|
||||||
" start_date = datetime.strptime(start_str, \"%d/%m/%Y\").date()\n", |
|
||||||
" end_date = datetime.strptime(end_str, \"%d/%m/%Y\").date()\n", |
|
||||||
" \n", |
|
||||||
" if start_date < flight_date < end_date:\n", |
|
||||||
" return \"Available\"\n", |
|
||||||
" else:\n", |
|
||||||
" return \"Not available for requested flight dates\"" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "9680afe1-65d8-4094-8a09-6ef37ebdad2b", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"\n", |
|
||||||
"availability_function = {\n", |
|
||||||
" \"name\": \"get_availability_period\",\n", |
|
||||||
" \"description\": \"Check if the requested flight dates are within the availability period of the flight schedule to the destination city. Call this whenever you need to know whether there is a flight to the requested city at the provided travel dates of the user, for example when a customer asks 'I want to book a flight to Tokyo on 5 Nov 2025'. \\\n", |
|
||||||
" If the user's date does not include a year, the date will refer to a date after the current date. State in your response whether there will be a flight to the destination city at the requested flight date. \\\n", |
|
||||||
" For example, an availability of '01/08/2025-31/10/2025' means that there are flights between 01 Aug 25 and 31 Oct 2025. \\\n", |
|
||||||
" Parse the user's flight date as string in the format DD-MM-YYYY or DD-MM if no year is given\",\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", |
|
||||||
" \"flight_date\": {\n", |
|
||||||
" \"type\": \"string\",\n", |
|
||||||
" \"description\": \"The date on which the customer wants to travel\",\n", |
|
||||||
" },\n", |
|
||||||
" },\n", |
|
||||||
" \"required\": [\"destination_city\", \"flight_date\"],\n", |
|
||||||
" \"additionalProperties\": False\n", |
|
||||||
" }\n", |
|
||||||
"}" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "bdca8679-935f-4e7f-97e6-e71a4d4f228c", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# And this is included in a list of tools:\n", |
|
||||||
"\n", |
|
||||||
"tools = [{\"type\": \"function\", \"function\": price_function}, {\"type\": \"function\", \"function\": availability_function}]" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "markdown", |
|
||||||
"id": "c3d3554f-b4e3-4ce7-af6f-68faa6dd2340", |
|
||||||
"metadata": {}, |
|
||||||
"source": [ |
|
||||||
"## Getting OpenAI to use our Tool\n", |
|
||||||
"\n", |
|
||||||
"There's some fiddly stuff to allow OpenAI \"to call our tool\"\n", |
|
||||||
"\n", |
|
||||||
"What we actually do is give the LLM the opportunity to inform us that it wants us to run the tool.\n", |
|
||||||
"\n", |
|
||||||
"Here's how the new chat function looks:" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "ce9b0744-9c78-408d-b9df-9f6fd9ed78cf", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"def chat(message, history):\n", |
|
||||||
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", |
|
||||||
" response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", |
|
||||||
"\n", |
|
||||||
" if response.choices[0].finish_reason==\"tool_calls\":\n", |
|
||||||
" message = response.choices[0].message\n", |
|
||||||
" response = handle_tools(message)\n", |
|
||||||
" messages.append(message)\n", |
|
||||||
" print(f\"Message: \\n {messages}\")\n", |
|
||||||
" messages.append(response)\n", |
|
||||||
" print(f\"Tool call response: \\n {response}\")\n", |
|
||||||
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n", |
|
||||||
" \n", |
|
||||||
" return response.choices[0].message.content" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "b0992986-ea09-4912-a076-8e5603ee631f", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# We have to write that function handle_tool_call:\n", |
|
||||||
"\n", |
|
||||||
"def handle_tool_call(message):\n", |
|
||||||
" tool_call = message.tool_calls[0]\n", |
|
||||||
" arguments = json.loads(tool_call.function.arguments)\n", |
|
||||||
" city = arguments.get('destination_city')\n", |
|
||||||
" price = get_ticket_price(city)\n", |
|
||||||
" response = {\n", |
|
||||||
" \"role\": \"tool\",\n", |
|
||||||
" \"content\": json.dumps({\"destination_city\": city,\"price\": price}),\n", |
|
||||||
" \"tool_call_id\": tool_call.id\n", |
|
||||||
" }\n", |
|
||||||
" return response, city" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": 1, |
|
||||||
"id": "d772048a-310e-4ff1-8c20-3dd7edb14a19", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"# Extended function to handle two tools\n", |
|
||||||
"\n", |
|
||||||
"def handle_tools(message):\n", |
|
||||||
" print(f\"message.tool_calls:\\n {message.tool_calls}\")\n", |
|
||||||
" tool_call = message.tool_calls[0] \n", |
|
||||||
" if message.tool_calls[0].function.name == \"get_ticket_price\":\n", |
|
||||||
" arguments = json.loads(tool_call.function.arguments)\n", |
|
||||||
" city = arguments.get('destination_city')\n", |
|
||||||
" price = get_ticket_price(city)\n", |
|
||||||
" content = json.dumps({\"destination_city\": city,\"price\": price})\n", |
|
||||||
" elif message.tool_calls[0].function.name == \"get_availability_period\":\n", |
|
||||||
" arguments = json.loads(tool_call.function.arguments)\n", |
|
||||||
" city = arguments.get('destination_city')\n", |
|
||||||
" flight_date = arguments.get('flight_date')\n", |
|
||||||
" availability_dates = get_availability_period(city, flight_date)\n", |
|
||||||
" content = json.dumps({\"destination_city\": city,\"availability_dates\": availability_dates})\n", |
|
||||||
" \n", |
|
||||||
" response = {\n", |
|
||||||
" \"role\": \"tool\",\n", |
|
||||||
" \"content\": content,\n", |
|
||||||
" \"tool_call_id\": tool_call.id\n", |
|
||||||
" }\n", |
|
||||||
"\n", |
|
||||||
" return response" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"cell_type": "code", |
|
||||||
"execution_count": null, |
|
||||||
"id": "f4be8a71-b19e-4c2f-80df-f59ff2661f14", |
|
||||||
"metadata": {}, |
|
||||||
"outputs": [], |
|
||||||
"source": [ |
|
||||||
"gr.ChatInterface(fn=chat, type=\"messages\").launch()" |
|
||||||
] |
|
||||||
} |
|
||||||
], |
|
||||||
"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 |
|
||||||
} |
|
Loading…
Reference in new issue