mirror of
https://github.com/Shubhamsaboo/awesome-llm-apps.git
synced 2026-03-11 17:48:31 -05:00
Add calendar (.ics) export to travel agent apps
This commit is contained in:
@@ -5,6 +5,7 @@ This Streamlit app is an AI-powered travel Agent that generates personalized tra
|
||||
- Research and discover exciting travel destinations, activities, and accommodations
|
||||
- Customize your itinerary based on the number of days you want to travel
|
||||
- Utilize the power of GPT-4o to generate intelligent and personalized travel plans
|
||||
- Download your itinerary as a calendar (.ics) file to import into Google Calendar, Apple Calendar, or other calendar apps
|
||||
|
||||
### How to get Started?
|
||||
|
||||
@@ -32,8 +33,29 @@ pip install -r requirements.txt
|
||||
streamlit run travel_agent.py
|
||||
```
|
||||
|
||||
For local LLM usage (with Ollama):
|
||||
```bash
|
||||
streamlit run local_travel_agent.py
|
||||
```
|
||||
|
||||
### How it Works?
|
||||
|
||||
The AI Travel Agent has two main components:
|
||||
- Researcher: Responsible for generating search terms based on the user's destination and travel duration, and searching the web for relevant activities and accommodations using SerpAPI.
|
||||
- Planner: Takes the research results and user preferences to generate a personalized draft itinerary that includes suggested activiti
|
||||
- **Researcher:** Responsible for generating search terms based on the user's destination and travel duration, and searching the web for relevant activities and accommodations using SerpAPI.
|
||||
- **Planner:** Takes the research results and user preferences to generate a personalized draft itinerary that includes suggested activities, dining options, and accommodations.
|
||||
|
||||
### Using the Calendar Download Feature
|
||||
|
||||
After generating your travel itinerary:
|
||||
1. Click the "Download Itinerary as Calendar (.ics)" button that appears next to the "Generate Itinerary" button
|
||||
2. Save the .ics file to your computer
|
||||
3. Import the file into your preferred calendar application (Google Calendar, Apple Calendar, Outlook, etc.)
|
||||
4. Each day of your itinerary will appear as an all-day event in your calendar
|
||||
5. The complete details for each day's activities are included in the event description
|
||||
|
||||
This feature makes it easy to keep track of your travel plans and have your itinerary available on all your devices, even offline.
|
||||
|
||||
### Local vs Cloud Version
|
||||
|
||||
- **travel_agent.py**: Uses OpenAI's GPT-4o for high-quality itineraries (requires OpenAI API key)
|
||||
- **local_travel_agent.py**: Uses Ollama for local LLM inference without sending data to external APIs (requires Ollama to be installed and running)
|
||||
@@ -2,12 +2,70 @@ from textwrap import dedent
|
||||
from agno.agent import Agent
|
||||
from agno.tools.serpapi import SerpApiTools
|
||||
import streamlit as st
|
||||
import re
|
||||
from agno.models.ollama import Ollama
|
||||
from icalendar import Calendar, Event
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def generate_ics_content(plan_text:str, start_date: datetime = None) -> bytes:
|
||||
"""
|
||||
Generate an ICS calendar file from a travel itinerary text.
|
||||
|
||||
Args:
|
||||
plan_text: The travel itinerary text
|
||||
start_date: Optional start date for the itinerary (defaults to today)
|
||||
|
||||
Returns:
|
||||
bytes: The ICS file content as bytes
|
||||
"""
|
||||
cal = Calendar()
|
||||
cal.add('prodid','-//AI Travel Planner//github.com//' )
|
||||
cal.add('version', '2.0')
|
||||
|
||||
if start_date is None:
|
||||
start_date = datetime.today()
|
||||
|
||||
# Split the plan into days
|
||||
day_pattern = re.compile(r'Day (\d+)[:\s]+(.*?)(?=Day \d+|$)', re.DOTALL)
|
||||
days = day_pattern.findall(plan_text)
|
||||
|
||||
if not days: # If no day pattern found, create a single all-day event with the entire content
|
||||
event = Event()
|
||||
event.add('summary', "Travel Itinerary")
|
||||
event.add('description', plan_text)
|
||||
event.add('dtstart', start_date.date())
|
||||
event.add('dtend', start_date.date())
|
||||
event.add("dtstamp", datetime.now())
|
||||
cal.add_component(event)
|
||||
else:
|
||||
# Process each day
|
||||
for day_num, day_content in days:
|
||||
day_num = int(day_num)
|
||||
current_date = start_date + timedelta(days=day_num - 1)
|
||||
|
||||
# Create a single event for the entire day
|
||||
event = Event()
|
||||
event.add('summary', f"Day {day_num} Itinerary")
|
||||
event.add('description', day_content.strip())
|
||||
|
||||
# Make it an all-day event
|
||||
event.add('dtstart', current_date.date())
|
||||
event.add('dtend', current_date.date())
|
||||
event.add("dtstamp", datetime.now())
|
||||
cal.add_component(event)
|
||||
|
||||
return cal.to_ical()
|
||||
|
||||
|
||||
# Set up the Streamlit app
|
||||
st.title("AI Travel Planner using Llama-3.2 ✈️")
|
||||
st.title("AI Travel Planner using Llama-3.2 ")
|
||||
st.caption("Plan your next adventure with AI Travel Planner by researching and planning a personalized itinerary on autopilot using local Llama-3")
|
||||
|
||||
# Initialize session state to store the generated itinerary
|
||||
if 'itinerary' not in st.session_state:
|
||||
st.session_state.itinerary = None
|
||||
|
||||
# Get SerpAPI key from the user
|
||||
serp_api_key = st.text_input("Enter Serp API Key for Search functionality", type="password")
|
||||
|
||||
@@ -15,7 +73,7 @@ if serp_api_key:
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Searches for travel destinations, activities, and accommodations based on user preferences",
|
||||
model=Ollama(id="llama3.2", max_tokens=1024),
|
||||
model=Ollama(id="llama3.2"),
|
||||
description=dedent(
|
||||
"""\
|
||||
You are a world-class travel researcher. Given a travel destination and the number of days the user wants to travel for,
|
||||
@@ -35,7 +93,7 @@ if serp_api_key:
|
||||
planner = Agent(
|
||||
name="Planner",
|
||||
role="Generates a draft itinerary based on user preferences and research results",
|
||||
model=Ollama(id="llama3.2", max_tokens=1024),
|
||||
model=Ollama(id="llama3.2"),
|
||||
description=dedent(
|
||||
"""\
|
||||
You are a senior travel planner. Given a travel destination, the number of days the user wants to travel for, and a list of research results,
|
||||
@@ -57,8 +115,27 @@ if serp_api_key:
|
||||
destination = st.text_input("Where do you want to go?")
|
||||
num_days = st.number_input("How many days do you want to travel for?", min_value=1, max_value=30, value=7)
|
||||
|
||||
if st.button("Generate Itinerary"):
|
||||
with st.spinner("Processing..."):
|
||||
# Get the response from the assistant
|
||||
response = planner.run(f"{destination} for {num_days} days", stream=False)
|
||||
st.write(response.content)
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
if st.button("Generate Itinerary"):
|
||||
with st.spinner("Processing..."):
|
||||
# Get the response from the assistant
|
||||
response = planner.run(f"{destination} for {num_days} days", stream=False)
|
||||
# Store the response in session state
|
||||
st.session_state.itinerary = response.content
|
||||
st.write(response.content)
|
||||
|
||||
# Only show download button if there's an itinerary
|
||||
with col2:
|
||||
if st.session_state.itinerary:
|
||||
# Generate the ICS file
|
||||
ics_content = generate_ics_content(st.session_state.itinerary)
|
||||
|
||||
# Provide the file for download
|
||||
st.download_button(
|
||||
label="Download Itinerary as Calendar (.ics)",
|
||||
data=ics_content,
|
||||
file_name="travel_itinerary.ics",
|
||||
mime="text/calendar"
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
streamlit
|
||||
agno
|
||||
openai
|
||||
google-search-results
|
||||
google-search-results
|
||||
icalendar
|
||||
@@ -2,12 +2,69 @@ from textwrap import dedent
|
||||
from agno.agent import Agent
|
||||
from agno.tools.serpapi import SerpApiTools
|
||||
import streamlit as st
|
||||
import re
|
||||
from agno.models.openai import OpenAIChat
|
||||
from icalendar import Calendar, Event
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def generate_ics_content(plan_text:str, start_date: datetime = None) -> bytes:
|
||||
"""
|
||||
Generate an ICS calendar file from a travel itinerary text.
|
||||
|
||||
Args:
|
||||
plan_text: The travel itinerary text
|
||||
start_date: Optional start date for the itinerary (defaults to today)
|
||||
|
||||
Returns:
|
||||
bytes: The ICS file content as bytes
|
||||
"""
|
||||
cal = Calendar()
|
||||
cal.add('prodid','-//AI Travel Planner//github.com//' )
|
||||
cal.add('version', '2.0')
|
||||
|
||||
if start_date is None:
|
||||
start_date = datetime.today()
|
||||
|
||||
# Split the plan into days
|
||||
day_pattern = re.compile(r'Day (\d+)[:\s]+(.*?)(?=Day \d+|$)', re.DOTALL)
|
||||
days = day_pattern.findall(plan_text)
|
||||
|
||||
if not days: # If no day pattern found, create a single all-day event with the entire content
|
||||
event = Event()
|
||||
event.add('summary', "Travel Itinerary")
|
||||
event.add('description', plan_text)
|
||||
event.add('dtstart', start_date.date())
|
||||
event.add('dtend', start_date.date())
|
||||
event.add("dtstamp", datetime.now())
|
||||
cal.add_component(event)
|
||||
else:
|
||||
# Process each day
|
||||
for day_num, day_content in days:
|
||||
day_num = int(day_num)
|
||||
current_date = start_date + timedelta(days=day_num - 1)
|
||||
|
||||
# Create a single event for the entire day
|
||||
event = Event()
|
||||
event.add('summary', f"Day {day_num} Itinerary")
|
||||
event.add('description', day_content.strip())
|
||||
|
||||
# Make it an all-day event
|
||||
event.add('dtstart', current_date.date())
|
||||
event.add('dtend', current_date.date())
|
||||
event.add("dtstamp", datetime.now())
|
||||
cal.add_component(event)
|
||||
|
||||
return cal.to_ical()
|
||||
|
||||
# Set up the Streamlit app
|
||||
st.title("AI Travel Planner ✈️")
|
||||
st.title("AI Travel Planner ")
|
||||
st.caption("Plan your next adventure with AI Travel Planner by researching and planning a personalized itinerary on autopilot using GPT-4o")
|
||||
|
||||
# Initialize session state to store the generated itinerary
|
||||
if 'itinerary' not in st.session_state:
|
||||
st.session_state.itinerary = None
|
||||
|
||||
# Get OpenAI API key from user
|
||||
openai_api_key = st.text_input("Enter OpenAI API Key to access GPT-4o", type="password")
|
||||
|
||||
@@ -60,22 +117,41 @@ if openai_api_key and serp_api_key:
|
||||
destination = st.text_input("Where do you want to go?")
|
||||
num_days = st.number_input("How many days do you want to travel for?", min_value=1, max_value=30, value=7)
|
||||
|
||||
if st.button("Generate Itinerary"):
|
||||
with st.spinner("Researching your destination..."):
|
||||
# First get research results
|
||||
research_results = researcher.run(f"Research {destination} for a {num_days} day trip", stream=False)
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
if st.button("Generate Itinerary"):
|
||||
with st.spinner("Researching your destination..."):
|
||||
# First get research results
|
||||
research_results = researcher.run(f"Research {destination} for a {num_days} day trip", stream=False)
|
||||
|
||||
# Show research progress
|
||||
st.write(" Research completed")
|
||||
|
||||
with st.spinner("Creating your personalized itinerary..."):
|
||||
# Pass research results to planner
|
||||
prompt = f"""
|
||||
Destination: {destination}
|
||||
Duration: {num_days} days
|
||||
Research Results: {research_results.content}
|
||||
|
||||
Please create a detailed itinerary based on this research.
|
||||
"""
|
||||
response = planner.run(prompt, stream=False)
|
||||
# Store the response in session state
|
||||
st.session_state.itinerary = response.content
|
||||
st.write(response.content)
|
||||
|
||||
# Only show download button if there's an itinerary
|
||||
with col2:
|
||||
if st.session_state.itinerary:
|
||||
# Generate the ICS file
|
||||
ics_content = generate_ics_content(st.session_state.itinerary)
|
||||
|
||||
# Show research progress
|
||||
st.write("✓ Research completed")
|
||||
|
||||
with st.spinner("Creating your personalized itinerary..."):
|
||||
# Pass research results to planner
|
||||
prompt = f"""
|
||||
Destination: {destination}
|
||||
Duration: {num_days} days
|
||||
Research Results: {research_results.content}
|
||||
|
||||
Please create a detailed itinerary based on this research.
|
||||
"""
|
||||
response = planner.run(prompt, stream=False)
|
||||
st.write(response.content)
|
||||
# Provide the file for download
|
||||
st.download_button(
|
||||
label="Download Itinerary as Calendar (.ics)",
|
||||
data=ics_content,
|
||||
file_name="travel_itinerary.ics",
|
||||
mime="text/calendar"
|
||||
)
|
||||
Reference in New Issue
Block a user