Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import logging | |
| from datetime import datetime, timedelta | |
| from langchain_google_genai import ChatGoogleGenerativeAI | |
| from langchain.schema import SystemMessage, HumanMessage | |
| # Setup logging configuration | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") | |
| # ------------------------------------------------------------------------------- | |
| # Agent and Task Classes with Type Hints and Docstrings | |
| # ------------------------------------------------------------------------------- | |
| class Agent: | |
| def __init__(self, role: str, goal: str, backstory: str, personality: str = "", llm=None) -> None: | |
| """ | |
| Initialize an Agent with role, goal, backstory, personality, and assigned LLM. | |
| """ | |
| self.role = role | |
| self.goal = goal | |
| self.backstory = backstory | |
| self.personality = personality | |
| self.tools = [] # Initialize with empty list for future tool integrations | |
| self.llm = llm | |
| class Task: | |
| def __init__(self, description: str, agent: Agent, expected_output: str, context=None) -> None: | |
| """ | |
| Initialize a Task with its description, the responsible agent, expected output, and optional context. | |
| """ | |
| self.description = description | |
| self.agent = agent | |
| self.expected_output = expected_output | |
| self.context = context or [] | |
| # ------------------------------------------------------------------------------- | |
| # Initialize LLM | |
| # ------------------------------------------------------------------------------- | |
| google_api_key = os.getenv("GEMINI_API_KEY") # μ€μ Google API ν€ μ¬μ© | |
| if not google_api_key: | |
| logging.error("GEMINI_API_KEY is not set in the environment variables.") | |
| llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", google_api_key=google_api_key) | |
| # ------------------------------------------------------------------------------- | |
| # Define Travel Agents | |
| # ------------------------------------------------------------------------------- | |
| destination_research_agent = Agent( | |
| role="Destination Research Agent", | |
| goal=( | |
| "Research and provide comprehensive information about the destination including popular attractions, " | |
| "local culture, weather patterns, best times to visit, and local transportation options." | |
| ), | |
| backstory=( | |
| "An experienced travel researcher with extensive knowledge of global destinations. " | |
| "I specialize in uncovering both popular attractions and hidden gems that match travelers' interests." | |
| ), | |
| personality="Curious, detail-oriented, and knowledgeable about global cultures and travel trends.", | |
| llm=llm, | |
| ) | |
| accommodation_agent = Agent( | |
| role="Accommodation Agent", | |
| goal="Find and recommend suitable accommodations based on the traveler's preferences, budget, and location requirements.", | |
| backstory="A hospitality expert who understands different types of accommodations and can match travelers with their ideal places to stay.", | |
| personality="Attentive, resourceful, and focused on comfort and value.", | |
| llm=llm, | |
| ) | |
| transportation_agent = Agent( | |
| role="Transportation Agent", | |
| goal="Plan efficient transportation between the origin, destination, and all points of interest in the itinerary.", | |
| backstory="A logistics specialist with knowledge of global transportation systems, from flights to local transit options.", | |
| personality="Efficient, practical, and detail-oriented.", | |
| llm=llm, | |
| ) | |
| activities_agent = Agent( | |
| role="Activities & Attractions Agent", | |
| goal="Curate personalized activities and attractions that align with the traveler's interests, preferences, and time constraints.", | |
| backstory="An enthusiastic explorer who has experienced diverse activities around the world and knows how to match experiences to individual preferences.", | |
| personality="Enthusiastic, creative, and personable.", | |
| llm=llm, | |
| ) | |
| dining_agent = Agent( | |
| role="Dining & Culinary Agent", | |
| goal="Recommend dining experiences that showcase local cuisine while accommodating dietary preferences and budget considerations.", | |
| backstory="A culinary expert with knowledge of global food scenes and an appreciation for authentic local dining experiences.", | |
| personality="Passionate about food, culturally aware, and attentive to preferences.", | |
| llm=llm, | |
| ) | |
| itinerary_agent = Agent( | |
| role="Itinerary Integration Agent", | |
| goal="Compile all recommendations into a cohesive, day-by-day itinerary that optimizes time, minimizes travel fatigue, and maximizes enjoyment.", | |
| backstory="A master travel planner who understands how to balance activities, rest, and logistics to create the perfect travel experience.", | |
| personality="Organized, balanced, and practical.", | |
| llm=llm, | |
| ) | |
| # ------------------------------------------------------------------------------- | |
| # Define Chatbot Agent and Task for Interactive Conversation | |
| # ------------------------------------------------------------------------------- | |
| chatbot_agent = Agent( | |
| role="Chatbot Agent", | |
| goal="Engage in interactive conversation to answer travel-related queries.", | |
| backstory="A conversational AI assistant who provides instant, accurate travel information and recommendations.", | |
| personality="Friendly, conversational, and knowledgeable about travel.", | |
| llm=llm, | |
| ) | |
| chatbot_task = Task( | |
| description="Provide a conversational and detailed response to travel-related queries.", | |
| agent=chatbot_agent, | |
| expected_output="A friendly, helpful response to the user's query." | |
| ) | |
| # ------------------------------------------------------------------------------- | |
| # Define Other Travel Tasks | |
| # ------------------------------------------------------------------------------- | |
| destination_research_task = Task( | |
| description="""Research {destination} thoroughly, considering the traveler's interests in {preferences}. | |
| Efficient research parameters: | |
| - Prioritize research in these critical categories: | |
| * Top attractions that match specific {preferences} (not generic lists) | |
| * Local transportation systems with cost-efficiency analysis | |
| * Neighborhood breakdown with accommodation recommendations by budget tier | |
| * Seasonal considerations for the specific travel dates | |
| * Safety assessment with specific areas to embrace or avoid | |
| * Cultural norms that impact visitor experience (dress codes, tipping, etiquette) | |
| - Apply efficiency filters: | |
| * Focus exclusively on verified information from official tourism boards, recent travel guides, and reliable local sources | |
| * Analyze recent visitor reviews (< 6 months old) to identify changing conditions | |
| * Evaluate price-to-experience value for attractions instead of just popularity | |
| * Identify logistical clusters where multiple interests can be satisfied efficiently | |
| * Research off-peak times for popular attractions to minimize waiting | |
| * Evaluate digital tools (apps, passes, reservation systems) that streamline the visit | |
| - Create practical knowledge matrices: | |
| * Transportation method comparison (cost vs. time vs. convenience) | |
| * Weather impact on specific activities | |
| * Budget allocation recommendations based on preference priorities | |
| * Time-saving opportunity identification""", | |
| agent=destination_research_agent, | |
| expected_output="""Targeted destination brief containing: | |
| 1. Executive summary highlighting the 5 most relevant aspects based on {preferences} | |
| 2. Neighborhood analysis with accommodation recommendations mapped to specific interests | |
| 3. Transportation efficiency guide with cost/convenience matrix | |
| 4. Cultural briefing focusing only on need-to-know information that impacts daily activities | |
| 5. Seasonal advantages and challenges specific to travel dates | |
| 6. Digital resource toolkit (essential apps, websites, reservation systems) | |
| 7. Budget optimization strategies with price ranges for key experiences | |
| 8. Safety and health quick-reference including emergency contacts | |
| 9. Logistics efficiency map showing optimal activity clustering | |
| 10. Local insider advantage recommendations that save time or money | |
| Format should prioritize scannable information with bullet points, comparison tables, and decision matrices rather than lengthy prose.""" | |
| ) | |
| accommodation_task = Task( | |
| description="Find suitable accommodations in {destination} based on a {budget} budget and preferences for {preferences}.", | |
| agent=accommodation_agent, | |
| expected_output="List of recommended accommodations with details on location, amenities, price range, and availability." | |
| ) | |
| transportation_task = Task( | |
| description="Plan transportation from {origin} to {destination} and local transportation options during the stay.", | |
| agent=transportation_agent, | |
| expected_output="Transportation plan including flights/routes to the destination and recommendations for getting around locally." | |
| ) | |
| activities_task = Task( | |
| description="""Suggest activities and attractions in {destination} that align with interests in {preferences}. | |
| Detailed requirements: | |
| - Categorize activities into: Cultural Experiences, Outdoor Adventures, Culinary Experiences, | |
| Entertainment & Nightlife, Family-Friendly Activities, and Local Hidden Gems | |
| - For each activity, include: | |
| * Detailed description with historical/cultural context where relevant | |
| * Precise location with neighborhood information | |
| * Operating hours with seasonal variations noted | |
| * Pricing information with different ticket options/packages | |
| * Accessibility considerations for travelers with mobility limitations | |
| * Recommended duration for the activity (minimum and ideal time) | |
| * Best time of day/week/year to visit | |
| * Crowd levels by season | |
| * Photography opportunities and restrictions | |
| * Required reservations or booking windows | |
| - Include a mix of iconic must-see attractions and off-the-beaten-path experiences | |
| - Consider weather patterns in {destination} during travel period | |
| - Analyze the {preferences} to match specific personality types and interest levels | |
| - Include at least 2-3 rainy day alternatives for outdoor activities | |
| - Provide local transportation options to reach each attraction | |
| - Note authentic local experiences that provide cultural immersion | |
| - Flag any activities requiring special equipment, permits, or physical fitness levels""", | |
| agent=activities_agent, | |
| expected_output="""Comprehensive curated list of activities and attractions with: | |
| 1. Clear categorization by type (cultural, outdoor, culinary, entertainment, family-friendly, hidden gems) | |
| 2. Detailed descriptions that include historical and cultural context | |
| 3. Complete practical information (hours, pricing, location, accessibility) | |
| 4. Time optimization recommendations (best time to visit, how to avoid crowds) | |
| 5. Personalized matches explaining why each activity aligns with specific {preferences} | |
| 6. Local transportation details to reach each attraction | |
| 7. Alternative options for inclement weather or unexpected closures | |
| 8. Insider tips from locals that enhance the experience | |
| 9. Suggested combinations of nearby activities for efficient itinerary planning | |
| 10. Risk level assessment and safety considerations where applicable | |
| 11. Sustainability impact and responsible tourism notes | |
| 12. Photographic highlights and optimal viewing points | |
| Format should include a summary table for quick reference followed by detailed cards for each activity.""" | |
| ) | |
| dining_task = Task( | |
| description="Recommend dining experiences in {destination} that showcase local cuisine while considering {preferences}.", | |
| agent=dining_agent, | |
| expected_output="List of recommended restaurants and food experiences with cuisine types, price ranges, and special notes." | |
| ) | |
| itinerary_task = Task( | |
| description="""Create a day-by-day itinerary for a {duration} trip to {destination} from {origin}, incorporating all recommendations. | |
| Detailed requirements: | |
| - Begin with arrival logistics including airport transfer options, check-in times, and first-day orientation activities | |
| - Structure each day with: | |
| * Morning, afternoon, and evening activity blocks with precise timing | |
| * Estimated travel times between locations using various transportation methods | |
| * Buffer time for rest, spontaneous exploration, and unexpected delays | |
| * Meal recommendations with reservation details and backup options | |
| * Sunset/sunrise opportunities for optimal photography or experiences | |
| - Apply intelligent sequencing to: | |
| * Group attractions by geographic proximity to minimize transit time | |
| * Schedule indoor activities strategically for predicted weather patterns | |
| * Balance high-energy activities with relaxation periods | |
| * Alternate between cultural immersion and entertainment experiences | |
| * Account for opening days/hours of attractions and potential closures | |
| - Include practical timing considerations: | |
| * Museum/attraction fatigue limitations | |
| * Jet lag recovery for first 1-2 days | |
| * Time zone adjustment strategies | |
| * Local rush hours and traffic patterns to avoid | |
| * Cultural norms for meal times and business hours | |
| - End with departure logistics including check-out procedures, airport transfer timing, and luggage considerations | |
| - Add specialized planning elements: | |
| * Local festivals or events coinciding with the travel dates | |
| * Free time blocks for personal exploration or shopping | |
| * Contingency recommendations for weather disruptions | |
| * Early booking requirements for popular attractions/restaurants | |
| * Local emergency contacts and nearby medical facilities""", | |
| agent=itinerary_agent, | |
| expected_output="""Comprehensive day-by-day itinerary featuring: | |
| 1. Detailed timeline for each day with hour-by-hour scheduling and transit times | |
| 2. Color-coded activity blocks that visually distinguish between types of activities | |
| 3. Intelligent geographic clustering to minimize transportation time | |
| 4. Strategic meal placements with both reservation-required and casual options | |
| 5. Built-in flexibility with free time blocks and alternative suggestions | |
| 6. Weather-adaptive scheduling with indoor/outdoor activity balance | |
| 7. Energy level considerations throughout the trip arc | |
| 8. Cultural timing adaptations (accommodating local siesta times, religious observances, etc.) | |
| 9. Practical logistical details (bag storage options, dress code reminders, etc.) | |
| 10. Local transportation guidance including transit cards, apps, and pre-booking requirements | |
| 11. Visual map representation showing daily movement patterns | |
| 12. Key phrases in local language for each day's activities | |
| Format should include both a condensed overview calendar and detailed daily breakdowns with time, activity, location, notes, and contingency plans.""" | |
| ) | |
| # ------------------------------------------------------------------------------- | |
| # Helper Function to Run a Task with Full Agent & Task Information | |
| # ------------------------------------------------------------------------------- | |
| def run_task(task: Task, input_text: str) -> str: | |
| """ | |
| Executes the given task using the associated agent's LLM and returns the response content. | |
| """ | |
| try: | |
| if not isinstance(task, Task): | |
| raise ValueError(f"Expected 'task' to be an instance of Task, got {type(task)}") | |
| if not hasattr(task, 'agent') or not isinstance(task.agent, Agent): | |
| raise ValueError("Task must have a valid 'agent' attribute of type Agent.") | |
| system_input = ( | |
| f"Agent Details:\n" | |
| f"Role: {task.agent.role}\n" | |
| f"Goal: {task.agent.goal}\n" | |
| f"Backstory: {task.agent.backstory}\n" | |
| f"Personality: {task.agent.personality}\n" | |
| ) | |
| task_input = ( | |
| f"Task Details:\n" | |
| f"Task Description: {task.description}\n" | |
| f"Expected Output: {task.expected_output}\n" | |
| f"Input for Task:\n{input_text}\n" | |
| ) | |
| messages = [ | |
| SystemMessage(content=system_input), | |
| HumanMessage(content=task_input) | |
| ] | |
| response = task.agent.llm.invoke(messages) | |
| if not response or not response.content: | |
| raise ValueError("Empty response from LLM.") | |
| return response.content | |
| except Exception as e: | |
| logging.error(f"Error in task '{task.agent.role}': {e}") | |
| return f"Error in {task.agent.role}: {e}" | |
| # ------------------------------------------------------------------------------- | |
| # User Input Functions | |
| # ------------------------------------------------------------------------------- | |
| def get_user_input() -> dict: | |
| """ | |
| Collects user input for travel itinerary generation. | |
| """ | |
| print("\n=== Travel Itinerary Generator ===\n") | |
| origin = input("Enter your origin city/country: ") | |
| destination = input("Enter your destination city/country: ") | |
| duration = input("Enter trip duration (number of days): ") | |
| budget = input("Enter your budget level (budget, moderate, luxury): ") | |
| print("\nEnter your travel preferences and interests (comma-separated):") | |
| print("Examples: museums, hiking, food, shopping, beaches, history, nightlife, family-friendly, etc.") | |
| preferences = input("> ") | |
| special_requirements = input("\nAny special requirements or notes (dietary restrictions, accessibility needs, etc.)? ") | |
| return { | |
| "origin": origin, | |
| "destination": destination, | |
| "duration": duration, | |
| "budget": budget, | |
| "preferences": preferences, | |
| "special_requirements": special_requirements | |
| } | |
| # ------------------------------------------------------------------------------- | |
| # Main Function to Generate Travel Itinerary | |
| # ------------------------------------------------------------------------------- | |
| def generate_travel_itinerary(user_input: dict) -> str: | |
| """ | |
| Generates a personalized travel itinerary by sequentially running defined tasks. | |
| """ | |
| print("\nGenerating your personalized travel itinerary...\n") | |
| # Create input context using f-string formatting | |
| input_context = ( | |
| f"Travel Request Details:\n" | |
| f"Origin: {user_input['origin']}\n" | |
| f"Destination: {user_input['destination']}\n" | |
| f"Duration: {user_input['duration']} days\n" | |
| f"Budget Level: {user_input['budget']}\n" | |
| f"Preferences/Interests: {user_input['preferences']}\n" | |
| f"Special Requirements: {user_input['special_requirements']}\n" | |
| ) | |
| # Step 1: Destination Research | |
| print("Researching your destination...") | |
| destination_info = run_task(destination_research_task, input_context) | |
| print("β Destination research completed") | |
| # Step 2: Accommodation Recommendations | |
| print("Finding ideal accommodations...") | |
| accommodation_info = run_task(accommodation_task, input_context) | |
| print("β Accommodation recommendations completed") | |
| # Step 3: Transportation Planning | |
| print("Planning transportation...") | |
| transportation_info = run_task(transportation_task, input_context) | |
| print("β Transportation planning completed") | |
| # Step 4: Activities & Attractions | |
| print("Curating activities and attractions...") | |
| activities_info = run_task(activities_task, input_context) | |
| print("β Activities and attractions curated") | |
| # Step 5: Dining Recommendations | |
| print("Finding dining experiences...") | |
| dining_info = run_task(dining_task, input_context) | |
| print("β Dining recommendations completed") | |
| # Step 6: Create Day-by-Day Itinerary | |
| print("Creating your day-by-day itinerary...") | |
| combined_info = ( | |
| input_context + "\n" | |
| "Destination Information:\n" + destination_info + "\n" | |
| "Accommodation Options:\n" + accommodation_info + "\n" | |
| "Transportation Plan:\n" + transportation_info + "\n" | |
| "Recommended Activities:\n" + activities_info + "\n" | |
| "Dining Recommendations:\n" + dining_info + "\n" | |
| ) | |
| itinerary = run_task(itinerary_task, combined_info) | |
| print("β Itinerary creation completed") | |
| print("β Itinerary generation completed") | |
| return itinerary | |
| # ------------------------------------------------------------------------------- | |
| # Save Itinerary to File | |
| # ------------------------------------------------------------------------------- | |
| def save_itinerary_to_file(itinerary: str, user_input: dict, output_dir: str = None) -> str: | |
| """ | |
| Saves the generated itinerary to a text file and returns the filepath. | |
| """ | |
| date_str = datetime.now().strftime("%Y-%m-%d") | |
| filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt" | |
| if output_dir: | |
| if not os.path.exists(output_dir): | |
| try: | |
| os.makedirs(output_dir) | |
| logging.info(f"Created output directory: {output_dir}") | |
| except Exception as e: | |
| logging.error(f"Error creating directory {output_dir}: {e}") | |
| return "" | |
| filepath = os.path.join(output_dir, filename) | |
| else: | |
| filepath = filename | |
| try: | |
| with open(filepath, "w", encoding="utf-8") as f: | |
| f.write(itinerary) | |
| logging.info(f"Your itinerary has been saved as: {filepath}") | |
| return filepath | |
| except Exception as e: | |
| logging.error(f"Error saving itinerary: {e}") | |
| return "" | |
| # ------------------------------------------------------------------------------- | |
| # Main Function | |
| # ------------------------------------------------------------------------------- | |
| def main() -> None: | |
| """ | |
| Main entry point for the travel itinerary generator application. | |
| """ | |
| print("Welcome to BlockX Travel Itinerary Generator!") | |
| print("This AI-powered tool will create a personalized travel itinerary based on your preferences.") | |
| user_input = get_user_input() | |
| print("\nWhere would you like to save the itinerary?") | |
| print("Press Enter to save in the current directory, or specify a path:") | |
| output_dir = input("> ").strip() or None | |
| itinerary = generate_travel_itinerary(user_input) | |
| filepath = save_itinerary_to_file(itinerary, user_input, output_dir) | |
| if filepath: | |
| print(f"\nYour personalized travel itinerary is ready! Open {filepath} to view it.") | |
| print("Thank you for using BlockX Travel Itinerary Generator!") | |
| if __name__ == "__main__": | |
| main() | |