import requests import hashlib import datetime import streamlit as st import pandas as pd import openai import os from langchain.chat_models import ChatOpenAI from langchain.chains import LLMChain from langchain.prompts import PromptTemplate # Make sure OpenAI's API key is set openai.api_key = os.getenv("OPENAI_API_KEY") if not openai.api_key: raise ValueError("OpenAI API key not set. Check your environment variables.") # Hotelbeds API credentials hotelbeds_api_key = "95ce3e45a02fc6fd9720ecc013a6f674" hotelbeds_api_secret = "785150201f" # Function to generate the API signature def generate_signature(): local_timestamp = int(datetime.datetime.now().timestamp()) assemble = hotelbeds_api_key + hotelbeds_api_secret + str(local_timestamp) signature = hashlib.sha256(assemble.encode()).hexdigest() return signature # Function to get geo-coordinates from a location name using OpenAI API through Langchain import re def get_coordinates(location_name): prompt_template = PromptTemplate( input_variables=["location"], template="What are the exact latitude and longitude of {location}? Please provide the values in decimal degrees." ) llm = ChatOpenAI(model="gpt-4", openai_api_key=openai.api_key) chain = LLMChain(llm=llm, prompt=prompt_template) result = chain.run(location=location_name).strip() try: # Use regular expressions to find latitude and longitude in the text lat_lon_match = re.findall(r"(-?\d+\.\d+)°?\s*([NSEW])", result) if lat_lon_match and len(lat_lon_match) == 2: # Extract latitude and longitude from regex matches latitude, lat_dir = lat_lon_match[0] longitude, lon_dir = lat_lon_match[1] # Convert the strings to float and adjust sign according to the hemisphere latitude = float(latitude) * (-1 if lat_dir in ['S', 's'] else 1) longitude = float(longitude) * (-1 if lon_dir in ['W', 'w'] else 1) return latitude, longitude else: raise ValueError("Could not find both latitude and longitude in the response") except Exception as e: st.error(f"Unable to parse coordinates from the AI's response: '{result}'. Error: {str(e)}") return None, None # Function to make the POST request to the Hotelbeds API and handle pagination def fetch_activities(latitude, longitude, from_date, to_date, language="en", paxes=[{"age": 5}, {"age": 70}], order="DEFAULT"): url = "https://api.test.hotelbeds.com/activity-api/3.0/activities/availability" signature = generate_signature() headers = { "Content-Type": "application/json", "Api-Key": hotelbeds_api_key, "X-Signature": signature, "Accept": "application/json", } payload = { "filters": [ { "searchFilterItems": [ { "type": "gps", "latitude": latitude, "longitude": longitude } ] } ], "from": from_date, "to": to_date, "language": language, "paxes": paxes, "order": order } activities = [] page = 1 items_per_page = 100 total_items = 0 while True: payload['pagination'] = {"page": page, "itemsPerPage": items_per_page} response = requests.post(url, headers=headers, json=payload) data = response.json() if response.status_code != 200 or 'errors' in data and data['errors']: st.error(f"Error fetching activities: {response.status_code}, Details: {data['errors']}") return None if 'pagination' in data: total_items = data['pagination']['totalItems'] items_per_page = data['pagination']['itemsPerPage'] activities.extend(data.get('activities', [])) if 'pagination' not in data or total_items <= items_per_page * page: break page += 1 return activities # Streamlit app st.title("Hotelbeds Activity Availability Checker") location_name = st.text_input("Location Name", value="New York City") from_date = st.date_input("From Date", value=pd.to_datetime("2024-06-20")) to_date = st.date_input("To Date", value=pd.to_datetime("2024-06-24")) if st.button("Check Availability"): latitude, longitude = get_coordinates(location_name) activities = fetch_activities(latitude, longitude, from_date.isoformat(), to_date.isoformat()) if activities: activity_details = [] for activity in activities: name = activity['content']['name'] adult_price = next( (amount['amount'] for amount in activity['modalities'][0]['amountsFrom'] if amount['paxType'] == 'ADULT'), None ) if adult_price is not None: activity_details.append(f"{name} - ${adult_price:.2f}") else: activity_details.append(name) st.json(activity_details) st.write(f"Total number of activities: {len(activity_details)}") else: st.error("No activities found or an error occurred.")