993
week2/community-contributions/Vacation_Planner.ipynb
Normal file
993
week2/community-contributions/Vacation_Planner.ipynb
Normal file
@@ -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": [
|
||||
"<div><iframe src=\"http://127.0.0.1:7860/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
|
||||
],
|
||||
"text/plain": [
|
||||
"<IPython.core.display.HTML object>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": []
|
||||
},
|
||||
"execution_count": 27,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"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",
|
||||
" # date_input = gr.DateTime()\n",
|
||||
" # output_box = gr.Textbox(label=\"UNIX Timestamp + API URL\", lines=3)\n",
|
||||
"\n",
|
||||
" with gr.Row():\n",
|
||||
" entry = gr.Textbox(label=\"Chat with our AI Assistant:\")\n",
|
||||
" with gr.Row():\n",
|
||||
" speak = gr.Button(\"click for voice search\") \n",
|
||||
" with gr.Row():\n",
|
||||
" clear = gr.Button(\"Clear\")\n",
|
||||
"\n",
|
||||
" def listen(history):\n",
|
||||
" message, history=listen2(history)\n",
|
||||
" return message, history\n",
|
||||
"\n",
|
||||
" def do_entry(message, history):\n",
|
||||
" history += [{\"role\":\"user\", \"content\":message}]\n",
|
||||
" return \"\", history\n",
|
||||
"\n",
|
||||
" # entry.submit(get_unix_timestamp, inputs=[date_input], outputs=[output_box])\n",
|
||||
" entry.submit(do_entry, inputs=[entry, chatbot], outputs=[entry, chatbot]).then(\n",
|
||||
" # chat, inputs=chatbot, outputs=[chatbot, image_output]\n",
|
||||
" chat, inputs=[chatbot], outputs=[chatbot]\n",
|
||||
" )\n",
|
||||
" speak.click(listen, inputs=[chatbot], outputs=[entry, chatbot]).then(\n",
|
||||
" chat, inputs=[chatbot], outputs=[chatbot]\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": "6507811e-9f98-4b8b-a482-9b0089c60db2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f3d3cf51-d2ae-4767-aa04-d8d6feb785bd",
|
||||
"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.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user