From 398a717958c46c1ff316bd91bb41e0610df675b9 Mon Sep 17 00:00:00 2001 From: arunabeshc <39411643+arunabeshc@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:44:47 +0530 Subject: [PATCH] Create Vacation_Planner.ipynb Vacation Planner added --- .../Vacation_Planner.ipynb | 993 ++++++++++++++++++ 1 file changed, 993 insertions(+) create mode 100644 week2/community-contributions/Vacation_Planner.ipynb diff --git a/week2/community-contributions/Vacation_Planner.ipynb b/week2/community-contributions/Vacation_Planner.ipynb new file mode 100644 index 0000000..0d42d0c --- /dev/null +++ b/week2/community-contributions/Vacation_Planner.ipynb @@ -0,0 +1,993 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "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\n", + "import base64\n", + "from io import BytesIO\n", + "import tempfile\n", + "import subprocess\n", + "from pydub import AudioSegment\n", + "import time\n", + "import anthropic\n", + "from datetime import datetime, time\n", + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "717ea9d4-1e72-4035-b7c5-5d61da5b8ea3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenAI API Key exists and begins sk-proj-\n" + ] + } + ], + "source": [ + "# Initialization\n", + "\n", + "load_dotenv(override=True)\n", + "\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "open_weather_api_key=os.getenv('open_weather')\n", + "amadeus_api_key=os.getenv('amadeus_key')\n", + "amadeus_secret=os.getenv('amadeus_secret')\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", + "gpt_model = \"gpt-4o-mini\"\n", + "\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cc78f4fd-9920-4872-9117-90cd2aeb2a06", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"\"\"You are a helpful assistant. You plan vacations for users in the following chronological manner - \n", + "1) you ask the user (if they have not already confirmed) which destination they want to travel to - beaches or mountains or any other destination \n", + " the user prefers \n", + "2) ask the current location of the user (if they have not already shared), please make sure the user shares the name of an exact city or a nearby city \n", + " with an airport\n", + "3) you list the best nearby vacation destinations (each destination should have an airport or provide the nearest airport option) \n", + "4) you ask them their travel start date for the present year only (if they have not already shared the information) that is which date in 2025 should they start\n", + "5) you make multiple tool calls (use tool check_weather) for finding weather data for each location from the list (from step 3 above) \n", + " by using the location, latitude, longitude, and date_year (as start_date + 1 from the previous year); \n", + " Example, if the start date is June 3rd, 2025, your date_year will become June 4th, 2024. You mandatorily have to share the date with the tool call function.\n", + "6) you shortlist top two destinations with better weather conditions and ask the user to share his final selection (vacation destination) and the number of people \n", + " who will be travelling and also share detailed itenerary for both the options for the user to select. Make sure the start and end destinations remain the same. \n", + " Example, if your onward journey is from bangalore to bali, the trip should end in bali, so that the user can avail the return flight from bali to bangalore.\n", + "7) after the user confirms the final selection and the number of heads(number of people availing the vacation) denoted by \"no\", you confirm \n", + " with the user, before proceeding to call the check_flights tool call to get the exact flight expenses for a return trip. Share the following data \n", + " along with the tool call - origin, destination, departure_date, return_date, number of people, currency (in which the user will be checking the costs). \n", + " Make sure to pass the IATA codes for the origin and destination locations to the check_flights_function tool, as an example, if the user is travelling from \n", + " bangalore to goa, pass the origin and destinations as BLR (not bangalore) and GOI (not GOA). \n", + "8) post obtaining the tool result, analyze, share the flight details and expenses with the user. But don't go ahead and book tickets.\n", + "9) Confirm with the user, the stay options that he/she has in mind - \n", + " a) How many rooms will be needed, then, post confirmation from the user, make the tool call \"check_stays_function\" to check the stay costs by\n", + " supplying the following parameters to the function (You should be having all above parameters by now, in case, anything is missing, ask the user \n", + " before proceeding)-\n", + " i) IATA code of the destination city, example if the user is travelling to goa, it will be GOA\n", + " ii) The check-in date, keep this parameter the same as the start_date for the user\n", + " iii) number of people who will be travelling\n", + " iv) Number of rooms needed\n", + " v) The check-out date, keep this parameter the same as the return date for the user\n", + "11) As the final step, show a detailed summary to the user showing the suggested flight with expenses and the suggested stay with expenses for the travel duration,\n", + " and the user's total expenses for the trip. Example, if the user is travelling from bangalore to goa, and you have already checked the flight costs from step 8\n", + " above as INR 2000, and from step 9 you confirm the stay costs as 1000 per day for a 5-day trip, (this you know from step 6 while making the itenerary), the total\n", + " expenses will be 2000 + (1000x5) = 7000 INR. Display the details to the user. \n", + "\n", + " IMPORTANT NOTE - \n", + " i) You will not proceed with booking any stay or flight tickets after step 11, so never say - \"This is your detailed itenerary, may I proceed to \n", + " book?\", rather say \"Hope you like the itenerary, in case of any changes, let me know and I will help revise the plan.\"\n", + " \n", + "Example usage - \n", + "\n", + "user - plan me a vacation\n", + "assistant - where to? beach or mountain?\n", + "user - beach\n", + "assistant - what is your location?\n", + "user - India\n", + "assistant - At what time of the year do you wish to travel? And which city in India with an airport you will be travelling from?\n", + "user - June 1st, 2025, Bangalore, India\n", + "assistant - top tourist destinations are - goa, gokarna, andaman and nicobar islands, varkala. Do you want me to proceed?\n", + "or do you want to add some suggestions?\n", + "user - please proceed\n", + "assistant - [makes tool calls for each location - goa, gokarna, andaman and nicobar islands, and varkala\n", + "for 2nd June 2024 (previous year), supplying the latitude and longitude data for each, along with the date as start_date+1 and shortlist the \n", + "top two places with the best weather conditions and share \n", + "the details with the user] here you go, based on what you asked for, goa and gokarna seem to be your best options\n", + "considering the weather conditions over a similar period in the previous year. Please let me know your final selection and number of people who will \n", + "be travelling and your preferred currency for the calculations\n", + "user - I will select Goa and 2 people myself and my wife will be travelling. I want to see the costs in INR\n", + "assistant - [makes a final itenerary taking into consideration the information provided by the user. Decides the return date and shares the final details with \n", + "the user and asks him to confirm] here is your final itenerary \"xxx\" start date is June 1st, return date is June 6th. Is this fine or do you want to make few changes \n", + "to the itenerary or start and/or end dates?\n", + "user - please proceed\n", + "assistant - [makes the tool call check_flights_function and passes the following information - Origin: BLR, Destination: GOI, Departure date - 2025-06-01,\n", + "return date - 2025-06-06, no = 2 (number of people), INR (currency). Checks the cost of the return flight ticket as a response from the tool call, analyzes and \n", + "finally showcases the user the flight expenses] Here you go, please find the flight details and the expenses for the same \"xx\". Can you please confirm the number\n", + "of rooms you will be availing so that I can check the hotel details?\n", + "user - sure, it will be 1 room\n", + "assistant - [makes the final tool call check_stays_function to find hotel price details] So the hotel options are \"xxx\" the prices are mostly in the range \"xx\", You final\n", + "itenerary is \"xxx\" with flights booked from bangalore to goa as \"xx\" flight expense - \"xx\", hotel expense \"xx\", total expense \"xx\"\n", + "\n", + "Make sure that the travel start date is confirmed by the user and you are passing the travel start date + 1 \n", + "as the \"check_weather\" tool call argument. Also. make sure that in your final answer, do not disclose the exact date again which \n", + "you made the api call. Rather say - Based on the weather conditions over a similar period last year, I will recommend\n", + "location x and y. But make sure you pass the date parameter as start_date + 1 from the previous year (2024) to the check_weather tool call\n", + "\n", + "for the check_flights_function tool call, please confirm the currency every time\n", + "for the check_weather tool call, please provide the date_year field each time\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c919b13a-50b6-4510-8e9d-02cdfd95cb98", + "metadata": {}, + "outputs": [], + "source": [ + "def check_weather(location, latitudes, longitudes, date_year):\n", + " \n", + " print(location)\n", + " print(latitudes)\n", + " print(longitudes)\n", + " print(date_year)\n", + " # if not (len(location) == len(latitudes) == len(longitudes) == len(date_year)):\n", + " # raise ValueError(\"All input lists must have the same length.\")\n", + "\n", + " timestamp1=get_unix_timestamp(date_year)\n", + " weather_data = []\n", + "\n", + " url = (\n", + " f\"https://api.openweathermap.org/data/3.0/onecall/timemachine?\"\n", + " f\"lat={latitudes}&lon={longitudes}&dt={timestamp1}&appid={open_weather_api_key}&units=metric\"\n", + " )\n", + " print(url)\n", + " try:\n", + " response = requests.get(url)\n", + " response.raise_for_status()\n", + " data = response.json()\n", + "\n", + " # Use first available hourly data as representative\n", + " hourly = data.get(\"data\") or data.get(\"hourly\") or []\n", + " if not hourly:\n", + " raise ValueError(\"No hourly data found in response.\")\n", + "\n", + " weather_point = hourly[0]\n", + " temperature = weather_point.get(\"temp\")\n", + " weather_desc = weather_point.get(\"weather\", [{}])[0].get(\"description\", \"N/A\")\n", + "\n", + " precipitation = 0\n", + " precip_type = \"none\"\n", + " if \"rain\" in weather_point:\n", + " precipitation = weather_point[\"rain\"].get(\"1h\", 0)\n", + " precip_type = \"rain\"\n", + " elif \"snow\" in weather_point:\n", + " precipitation = weather_point[\"snow\"].get(\"1h\", 0)\n", + " precip_type = \"snow\"\n", + "\n", + " weather_data.append({\n", + " \"location\": location,\n", + " \"date_year\": timestamp1,\n", + " \"temperature\": temperature,\n", + " \"weather\": weather_desc,\n", + " \"precipitation_type\": precip_type,\n", + " \"precipitation_mm\": precipitation\n", + " })\n", + "\n", + " except requests.RequestException as e:\n", + " weather_data.append({\n", + " \"location\": location,\n", + " \"date_year\": timestamp1,\n", + " \"error\": f\"Request failed: {e}\"\n", + " })\n", + " except Exception as e:\n", + " weather_data.append({\n", + " \"location\": location,\n", + " \"date_year\": timestamp1,\n", + " \"error\": f\"Processing error: {e}\"\n", + " })\n", + "\n", + " print(weather_data)\n", + "\n", + " return weather_data\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "73c4e65a-5080-448a-b3be-0914b10f99f7", + "metadata": {}, + "outputs": [], + "source": [ + "# call_amadeus(\"BLR\",\"GOI\",\"2025-07-29\",\"2025-08-05\",2,\"INR\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7115bf68-dc5d-4b54-b5a2-07662e74af5f", + "metadata": {}, + "outputs": [], + "source": [ + "def extract_sorted_flights_by_price_with_baggage_weight(response_json):\n", + " results = []\n", + " \n", + " # Map carrier codes to full names\n", + " carrier_dict = response_json.get(\"dictionaries\", {}).get(\"carriers\", {})\n", + "\n", + " for offer in response_json.get(\"data\", []):\n", + " itineraries = offer.get(\"itineraries\", [])\n", + " traveler_pricing = offer.get(\"travelerPricings\", [])[0]\n", + " fare_details = traveler_pricing.get(\"fareDetailsBySegment\", [])\n", + " price = float(offer.get(\"price\", {}).get(\"total\", 0.0))\n", + " currency = offer.get(\"price\", {}).get(\"currency\", \"INR\")\n", + "\n", + " outbound_segment = itineraries[0][\"segments\"][0]\n", + " inbound_segment = itineraries[1][\"segments\"][0]\n", + "\n", + " outbound_airline = carrier_dict.get(outbound_segment[\"carrierCode\"], outbound_segment[\"carrierCode\"])\n", + " inbound_airline = carrier_dict.get(inbound_segment[\"carrierCode\"], inbound_segment[\"carrierCode\"])\n", + "\n", + " # Build baggage weight lookup\n", + " baggage_lookup = {\n", + " fare[\"segmentId\"]: fare.get(\"includedCheckedBags\", {}).get(\"weight\", \"N/A\")\n", + " for fare in fare_details\n", + " }\n", + "\n", + " summary = {\n", + " \"Price\": price,\n", + " \"Currency\": currency,\n", + " \"Departure Time\": outbound_segment[\"departure\"][\"at\"],\n", + " \"Return Time\": inbound_segment[\"departure\"][\"at\"],\n", + " \"Departure Airline\": outbound_airline,\n", + " \"Return Airline\": inbound_airline,\n", + " \"Check-in Baggage Weight\": {\n", + " \"Departure\": f'{baggage_lookup.get(outbound_segment[\"id\"], \"N/A\")}kg' if baggage_lookup.get(outbound_segment[\"id\"]) else \"N/A\",\n", + " \"Return\": f'{baggage_lookup.get(inbound_segment[\"id\"], \"N/A\")}kg' if baggage_lookup.get(inbound_segment[\"id\"]) else \"N/A\",\n", + " }\n", + " }\n", + "\n", + " results.append(summary)\n", + "\n", + " # Sort by price\n", + " sorted_results = sorted(results, key=lambda x: x[\"Price\"])\n", + " return sorted_results\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "6929ba76-bf75-490b-adc9-c43bf90ce72d", + "metadata": {}, + "outputs": [], + "source": [ + "# def get_city_iata_code(city_name):\n", + "# # Step 1: Get access token\n", + "# print(f\"finding iata code for {city_name}\")\n", + "# auth_response = requests.post(\n", + "# \"https://test.api.amadeus.com/v1/security/oauth2/token\",\n", + "# headers={\"Content-Type\": \"application/x-www-form-urlencoded\"},\n", + "# data={\n", + "# \"grant_type\": \"client_credentials\",\n", + "# \"client_id\": amadeus_api_key,\n", + "# \"client_secret\": amadeus_secret\n", + "# }\n", + "# )\n", + "# auth_response.raise_for_status()\n", + "# access_token = auth_response.json()[\"access_token\"]\n", + "\n", + "# # Step 2: Search for city IATA code\n", + "# location_response = requests.get(\n", + "# \"https://test.api.amadeus.com/v1/reference-data/locations\",\n", + "# headers={\"Authorization\": f\"Bearer {access_token}\"},\n", + "# params={\"keyword\": city_name, \"subType\": \"CITY\"}\n", + "# )\n", + "# location_response.raise_for_status()\n", + "# data = location_response.json().get(\"data\", [])\n", + "\n", + "# if not data:\n", + "# print(f\"No IATA code found for {city_name}\")\n", + "# return None\n", + "\n", + "# return data[0][\"iataCode\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "42a82601-1afa-4a0f-92bc-3cbfdfd9f119", + "metadata": {}, + "outputs": [], + "source": [ + "# # print(get_city_iata_code(\"bengaluru\"))\n", + "# def lower(s):\n", + "# result = \"\"\n", + "# for char in s:\n", + "# # Check if char is uppercase (ASCII 65–90)\n", + "# if 'A' <= char <= 'Z':\n", + "# # Convert to lowercase by adding 32 to ASCII value\n", + "# result += chr(ord(char) + 32)\n", + "# else:\n", + "# result += char\n", + "# return result" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "aa6f59ce-9c7d-46ec-945e-aa40ee88e392", + "metadata": {}, + "outputs": [], + "source": [ + "def call_amadeus(origin, destination, departure_date, return_date, no, currency):\n", + " # or1=get_city_iata_code(lower(origin))\n", + " # dest=get_city_iata_code(lower(destination))\n", + " # print(f\"iata codes origin - {or1}, destination - {dest}\")\n", + " or1=origin\n", + " dest=destination\n", + " print(f\"origin is {or1}, destination is {dest}\")\n", + " auth_response = requests.post(\n", + " \"https://test.api.amadeus.com/v1/security/oauth2/token\",\n", + " data={\n", + " \"grant_type\": \"client_credentials\",\n", + " \"client_id\": amadeus_api_key,\n", + " \"client_secret\": amadeus_secret\n", + " }\n", + " )\n", + " access_token = auth_response.json()['access_token']\n", + "\n", + " # Search flights\n", + " headers = {\"Authorization\": f\"Bearer {access_token}\"}\n", + " params = {\n", + " \"originLocationCode\": or1,\n", + " \"destinationLocationCode\": dest,\n", + " \"departureDate\": departure_date,\n", + " \"returnDate\": return_date,\n", + " \"adults\": 2,\n", + " \"nonStop\": \"false\",\n", + " \"currencyCode\": currency,\n", + " \"max\":4\n", + " }\n", + " response = requests.get(\n", + " \"https://test.api.amadeus.com/v2/shopping/flight-offers\",\n", + " headers=headers,\n", + " params=params\n", + " )\n", + " \n", + " # print(response.json())\n", + "\n", + " return extract_sorted_flights_by_price_with_baggage_weight(response.json())" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "973d6078-baf8-4e88-a9f2-529fff15dee6", + "metadata": {}, + "outputs": [], + "source": [ + "def get_access_token():\n", + " url = 'https://test.api.amadeus.com/v1/security/oauth2/token'\n", + " payload = {\n", + " 'grant_type': 'client_credentials',\n", + " 'client_id': amadeus_api_key,\n", + " 'client_secret': amadeus_secret\n", + " }\n", + "\n", + " response = requests.post(url, data=payload)\n", + " response.raise_for_status()\n", + " return response.json()['access_token']" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ad87f1f3-3fea-437b-9f4e-f1b46e1728fd", + "metadata": {}, + "outputs": [], + "source": [ + "def get_hotel_ids(city_code, radius_km):\n", + " print(\"--------------------checking hotel ids--------------------\")\n", + " token = get_access_token()\n", + " print(f\"Access Token: {token}\")\n", + " url = 'https://test.api.amadeus.com/v1/reference-data/locations/hotels/by-city'\n", + " headers = {\n", + " 'Authorization': f'Bearer {token}'\n", + " }\n", + " params = {\n", + " 'cityCode': city_code,\n", + " 'radius': radius_km,\n", + " 'radiusUnit': 'KM',\n", + " # 'amenities': 'SWIMMING_POOL', # Optional filter\n", + " # 'ratings': '3', # Optional filter\n", + " 'hotelSource': 'ALL'\n", + " }\n", + "\n", + " response = requests.get(url, headers=headers, params=params)\n", + " response.raise_for_status()\n", + " data = response.json().get('data', [])\n", + " hotel_ids = [hotel['hotelId'] for hotel in data]\n", + " \n", + " print(f\"✅ Found {len(hotel_ids)} hotels in {city_code}\")\n", + " return hotel_ids[:20]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7191f8a3-aabc-4f8e-bf11-635ecaf40c5d", + "metadata": {}, + "outputs": [], + "source": [ + "def get_hotel_offers(city_code, check_in_date, no,rooms, check_out_date):\n", + " print(\"---------------inside get hotel offers--------------\")\n", + " hotel_ids=get_hotel_ids(city_code,10)\n", + " \n", + " return get_hotel_offers_by_ids(hotel_ids,check_in_date,no, rooms,check_out_date)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e6323979-352c-4fb6-9fe7-216e3613513f", + "metadata": {}, + "outputs": [], + "source": [ + "def get_hotel_offers_by_ids(hotel_ids, check_in_date, adults, rooms, check_out_date):\n", + " print(\"--------------------checking hotel offers based on ids--------------------\")\n", + " token = get_access_token()\n", + " print(f\"Access Token: {token}\")\n", + " url = 'https://test.api.amadeus.com/v3/shopping/hotel-offers'\n", + " headers = {\n", + " 'Authorization': f'Bearer {token}'\n", + " }\n", + "\n", + " all_offers = []\n", + "\n", + " for hotel_id in hotel_ids:\n", + " params = {\n", + " 'hotelIds': hotel_id,\n", + " # 'adults': adults,\n", + " 'checkInDate': check_in_date,\n", + " 'checkOutDate': check_out_date\n", + " # 'roomQuantity': rooms,\n", + " # 'paymentPolicy': 'NONE',\n", + " # 'includeClosed': 'false',\n", + " # 'bestRateOnly': 'true',\n", + " # 'view': 'FULL',\n", + " # 'sort': 'PRICE'\n", + " }\n", + "\n", + " try:\n", + " print(f\"🔍 Checking hotel ID: {hotel_id}\")\n", + " response = requests.get(url, headers=headers, params=params)\n", + " response.raise_for_status()\n", + " offers = response.json()\n", + " if \"data\" in offers and offers[\"data\"]:\n", + " print(f\"✅ Found offers for hotel ID: {hotel_id}\")\n", + " all_offers.extend(offers[\"data\"])\n", + " else:\n", + " print(f\"⚠️ No offers returned for hotel ID: {hotel_id}\")\n", + " except requests.exceptions.HTTPError as e:\n", + " print(f\"❌ HTTPError for hotel ID {hotel_id}: {e}\")\n", + "\n", + " if all_offers:\n", + " return json.dumps({\"data\": all_offers}, indent=2)\n", + " else:\n", + " return json.dumps({\"message\": \"No valid hotel offers found.\"}, indent=2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "fa82a6d1-cd74-46aa-9b99-c56dc02cddff", + "metadata": {}, + "outputs": [], + "source": [ + "# print(get_hotel_offers(\"GOI\",\"2025-06-03\",2,1,\"2025-06-08\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "687e610d-0951-400b-b575-9a83b788bf79", + "metadata": {}, + "outputs": [], + "source": [ + "check_stays_function = {\n", + " \"name\": \"get_hotel_offers\",\n", + " \"description\": \"Call this tool whenever you need to check the hotel availability and prices for the vacation destination. You need to supply the city_code, check_in_date,\\\n", + " number of heads, and number of rooms\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"city_code\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The IATA code for the vacation destination\",\n", + " },\n", + " \"check_in_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the date when the user will be checking into the hotel\",\n", + " },\n", + " \"no\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the number of heads for which reservation needs to be made, that is, how many members should the reservation be made for\",\n", + " },\n", + " \"rooms\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The number of rooms to be reserved as confirmed by the user\",\n", + " },\n", + " \"check_out_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the date when the user will be checking out of the hotel\",\n", + " },\n", + " },\n", + " \"required\": [\"city_code\",\"check_in_date\",\"no\",\"rooms\",\"check_out_date\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "717913a3-aab8-4df7-b9a1-c4bbc649babd", + "metadata": {}, + "outputs": [], + "source": [ + "check_flights_function = {\n", + " \"name\": \"call_amadeus\",\n", + " \"description\": \"Call this tool whenever you need to check the flight prices and other details for a return \\\n", + " trip from the origin to the destination location (where the user wants to spend his vacation). Make sure that you \\\n", + " supply the origin, destination, departure date, return date, number of tickets, and the \\\n", + " currency in which the user would like to pay. Please note the details provided will be for the return trip and NOT one-way\\\n", + " \",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"origin\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"Origin location for the user - his origin city or a nearby city with an airport\",\n", + " },\n", + " \"destination\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"Destination location for the user - his vacation destination airport or airport \\\n", + " which is nearby to his vacation destination\",\n", + " },\n", + " \"departure_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the start date for the user's vacation\",\n", + " },\n", + " \"return_date\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the end date/ return date for the user's vacation\",\n", + " },\n", + " \"no\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the number of tickets to purchase\",\n", + " },\n", + " \"currency\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the currency in which payment is to be made\",\n", + " },\n", + " },\n", + " \"required\": [\"origin\",\"destination\",\"departure_date\",\"return_date\",\"no\",\"currency\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "d2628781-6f5e-4ac1-bbe3-2e08aa0aae0d", + "metadata": {}, + "outputs": [], + "source": [ + "check_weather_function = {\n", + " \"name\": \"check_weather\",\n", + " \"description\": \"Call this tool whenever you need to check the weather of a location for a specific\\\n", + " time from the previous year. The tool will require -\\\n", + " 1) the llm to supply details of one location (based on the category- beaches or mountains or any other category the user selects) \\\n", + " and to which the user might travel to, \\\n", + " 2) the latitude and longitude of that location. \\\n", + " 3) the date_year, which basically is (vacation start date + 1 from previous year.) - this is essentially the date against which the weather conditions are to be \\\n", + " checked. For simplicity, we would keep it as the vacation start date + 1 from the previous year. Example, if the user provides the date as june 3rd, 2025,\\\n", + " date_year will be june 4th, 2024.\\\n", + " This tool call will return a list of weather situations one year ago for the chosen location.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"location\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"One of the locations that is near the user's location based on the\\\n", + " category the user selects (beaches or mountains or any other destination category based on the user's choice)\",\n", + " },\n", + " \"lat\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The latitude of the location\",\n", + " },\n", + " \"long\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The longitude of the location\",\n", + " },\n", + " \"date_year\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The date of the previous year for which the weather needs to be fetched\",\n", + " }\n", + " },\n", + " \"required\": [\"location\",\"lat\",\"long\",\"date_year\"],\n", + " \"additionalProperties\": False\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "1d5d74a0-9c25-46a4-84ee-1f700bd55fa7", + "metadata": {}, + "outputs": [], + "source": [ + "# And this is included in a list of tools:\n", + "\n", + "tools = [{\"type\": \"function\", \"function\": check_weather_function},\n", + " {\"type\": \"function\", \"function\": check_flights_function},\n", + " {\"type\": \"function\", \"function\": check_stays_function}]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "fa18f535-f8a7-4386-b39a-df0f84d23406", + "metadata": {}, + "outputs": [], + "source": [ + "def play_audio(audio_segment):\n", + " temp_dir = tempfile.gettempdir()\n", + " temp_path = os.path.join(temp_dir, \"temp_audio.wav\")\n", + " try:\n", + " audio_segment.export(temp_path, format=\"wav\")\n", + " # time.sleep(3) # Student Dominic found that this was needed. You could also try commenting out to see if not needed on your PC\n", + " subprocess.call([\n", + " \"ffplay\",\n", + " \"-nodisp\",\n", + " \"-autoexit\",\n", + " \"-hide_banner\",\n", + " temp_path\n", + " ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n", + " finally:\n", + " try:\n", + " os.remove(temp_path)\n", + " except Exception:\n", + " pass\n", + " \n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"alloy\", # Also, try replacing with onyx\n", + " input=message\n", + " )\n", + " audio_stream = BytesIO(response.content)\n", + " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", + " play_audio(audio)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "b588d711-5f20-4a3a-9422-81a1fda8d5b0", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call1(name, args):\n", + " location = args.get('location')\n", + " lat = args.get('lat')\n", + " long = args.get('long')\n", + " date_year = args.get('date_year')\n", + " if name.replace('\"','') == \"check_weather\":\n", + " weather=check_weather(location, lat, long, date_year)\n", + " \n", + " return weather" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "4eaf63c6-d590-44b8-a508-6e99e314dee1", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call2(name, args):\n", + " origin = args.get('origin')\n", + " destination = args.get('destination')\n", + " departure_date = args.get('departure_date')\n", + " return_date = args.get('return_date')\n", + " no = args.get('no')\n", + " currency = args.get('currency')\n", + " if name.replace('\"','') == \"call_amadeus\":\n", + " flights=call_amadeus(origin, destination, departure_date, return_date,no,currency)\n", + " \n", + " return flights" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "dd85e8dc-6c40-4b6d-b1c3-0efe67093150", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call3(name, args):\n", + " city_code = args.get('city_code')\n", + " check_in_date = args.get('check_in_date')\n", + " no = args.get('no')\n", + " rooms = args.get('rooms')\n", + " check_out_date = args.get('check_out_date')\n", + " if name.replace('\"','') == \"get_hotel_offers\":\n", + " hotels=get_hotel_offers(city_code, check_in_date, no, rooms,check_out_date)\n", + " \n", + " return hotels" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "04a11068-96ab-40eb-9185-1177835a3de7", + "metadata": {}, + "outputs": [], + "source": [ + "def chat_open_ai(history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history \n", + " response = openai.chat.completions.create(model=gpt_model, messages=messages, tools=tools)\n", + "\n", + " tool_responses = []\n", + "\n", + " if response.choices[0].finish_reason == \"tool_calls\":\n", + " message = response.choices[0].message\n", + " tool_calls = message.tool_calls # renamed to avoid UnboundLocalError\n", + "\n", + " print(f\"tool calls \\n\\n {tool_calls}\")\n", + "\n", + " for tool_call in tool_calls:\n", + " tool_id = tool_call.id\n", + " name = tool_call.function.name\n", + " args = json.loads(tool_call.function.arguments)\n", + "\n", + " # Call the tool handler\n", + " result = \"\"\n", + " if name == \"check_weather\":\n", + " result = handle_tool_call1(name, args)\n", + " elif name == \"call_amadeus\":\n", + " result = handle_tool_call2(name, args)\n", + " elif name == \"get_hotel_offers\":\n", + " result = handle_tool_call3(name, args)\n", + "\n", + " tool_responses.append({\n", + " \"role\": \"tool\",\n", + " \"tool_call_id\": tool_id,\n", + " \"content\": json.dumps(result),\n", + " })\n", + "\n", + " print(f\"tool responses {tool_responses}\")\n", + " messages.append(message)\n", + " messages.extend(tool_responses) # important fix here\n", + "\n", + " response = openai.chat.completions.create(\n", + " model=gpt_model,\n", + " messages=messages,\n", + " tools=tools\n", + " )\n", + "\n", + " reply = response.choices[0].message.content\n", + " # talker(reply)\n", + " history += [{\"role\": \"assistant\", \"content\": reply}]\n", + "\n", + " return history\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "a2547bb0-43a5-4b1d-8b9a-95da15a11040", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(history):\n", + " # + [{\"role\": \"user\", \"content\": message}]\n", + " # if Model==\"Open AI\":\n", + " history = chat_open_ai(history)\n", + " # \n", + "\n", + " return history" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "36e11d99-9281-4efd-a792-dd4fa5935917", + "metadata": {}, + "outputs": [], + "source": [ + "def listen2(history):\n", + " import speech_recognition as sr\n", + "\n", + " r = sr.Recognizer()\n", + " with sr.Microphone() as source:\n", + " print(\"Speak now...\")\n", + " audio = r.listen(source, phrase_time_limit=30)\n", + " text=\"\"\n", + " try:\n", + " text = r.recognize_google(audio)\n", + " print(\"You said:\", text)\n", + " except sr.UnknownValueError:\n", + " print(\"Could not understand audio.\")\n", + "\n", + " history += [{\"role\":\"user\", \"content\":text}] \n", + " return \"\", history" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "54e18ba1-78c9-4435-9f12-50fb93ba41fc", + "metadata": {}, + "outputs": [], + "source": [ + "def get_unix_timestamp(date):\n", + " if date is None:\n", + " return \"Please select a date.\"\n", + " if isinstance(date, str):\n", + " # Convert timestamp (string) to datetime\n", + " date = datetime.strptime(date, \"%Y-%m-%d\").date()\n", + "\n", + " dt = datetime.combine(date, time(0, 0)) # Midnight UTC\n", + " unix_timestamp = int(dt.timestamp())\n", + " # url = f\"https://api.openweathermap.org/data/3.0/onecall/timemachine?lat=39.099724&lon=-94.578331&dt={unix_timestamp}&appid={open_weather_api_key}\"\n", + " return unix_timestamp" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "133904cf-4d72-4552-84a8-76650f334857", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7860\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "