Upload 15 files
Browse files- .gitignore +6 -0
- LICENSE +21 -0
- requirements.txt +6 -0
- streamlit_app.py +134 -0
- tools/__init__.py +0 -0
- tools/__pycache__/__init__.cpython-311.pyc +0 -0
- tools/__pycache__/browser_tools.cpython-311.pyc +0 -0
- tools/__pycache__/calculator_tools.cpython-311.pyc +0 -0
- tools/__pycache__/search_tools.cpython-311.pyc +0 -0
- tools/browser_tools.py +38 -0
- tools/calculator_tools.py +13 -0
- tools/search_tools.py +37 -0
- trip_agents.py +143 -0
- trip_tasks.py +86 -0
.gitignore
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
.DS_Store
|
| 3 |
+
__pycache__
|
| 4 |
+
agent
|
| 5 |
+
.streamlit/secrets.toml
|
| 6 |
+
.venv
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2024 Tony Kipkemboi
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
crewai
|
| 2 |
+
streamlit
|
| 3 |
+
openai
|
| 4 |
+
unstructured
|
| 5 |
+
pyowm
|
| 6 |
+
tools
|
streamlit_app.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Crew
|
| 2 |
+
from trip_agents import TripAgents, StreamToExpander
|
| 3 |
+
from trip_tasks import TripTasks
|
| 4 |
+
import streamlit as st
|
| 5 |
+
import datetime
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
st.set_page_config(page_icon="✈️", layout="wide")
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def icon(emoji: str):
|
| 12 |
+
"""Shows an emoji as a Notion-style page icon."""
|
| 13 |
+
st.write(
|
| 14 |
+
f'<span style="font-size: 78px; line-height: 1">{emoji}</span>',
|
| 15 |
+
unsafe_allow_html=True,
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class TripCrew:
|
| 20 |
+
|
| 21 |
+
def __init__(self, origin, cities, date_range, interests):
|
| 22 |
+
self.cities = cities
|
| 23 |
+
self.origin = origin
|
| 24 |
+
self.interests = interests
|
| 25 |
+
self.date_range = date_range
|
| 26 |
+
self.output_placeholder = st.empty()
|
| 27 |
+
|
| 28 |
+
def run(self):
|
| 29 |
+
agents = TripAgents()
|
| 30 |
+
tasks = TripTasks()
|
| 31 |
+
|
| 32 |
+
city_selector_agent = agents.city_selection_agent()
|
| 33 |
+
local_expert_agent = agents.local_expert()
|
| 34 |
+
travel_concierge_agent = agents.travel_concierge()
|
| 35 |
+
|
| 36 |
+
identify_task = tasks.identify_task(
|
| 37 |
+
city_selector_agent,
|
| 38 |
+
self.origin,
|
| 39 |
+
self.cities,
|
| 40 |
+
self.interests,
|
| 41 |
+
self.date_range
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
gather_task = tasks.gather_task(
|
| 45 |
+
local_expert_agent,
|
| 46 |
+
self.origin,
|
| 47 |
+
self.interests,
|
| 48 |
+
self.date_range
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
plan_task = tasks.plan_task(
|
| 52 |
+
travel_concierge_agent,
|
| 53 |
+
self.origin,
|
| 54 |
+
self.interests,
|
| 55 |
+
self.date_range
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
crew = Crew(
|
| 59 |
+
agents=[
|
| 60 |
+
city_selector_agent, local_expert_agent, travel_concierge_agent
|
| 61 |
+
],
|
| 62 |
+
tasks=[identify_task, gather_task, plan_task],
|
| 63 |
+
verbose=True
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
result = crew.kickoff()
|
| 67 |
+
self.output_placeholder.markdown(result)
|
| 68 |
+
|
| 69 |
+
return result
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
if __name__ == "__main__":
|
| 73 |
+
icon("🏖️ VacAIgent")
|
| 74 |
+
|
| 75 |
+
st.subheader("Let AI agents plan your next vacation!",
|
| 76 |
+
divider="rainbow", anchor=False)
|
| 77 |
+
|
| 78 |
+
import datetime
|
| 79 |
+
|
| 80 |
+
today = datetime.datetime.now().date()
|
| 81 |
+
next_year = today.year + 1
|
| 82 |
+
jan_16_next_year = datetime.date(next_year, 1, 10)
|
| 83 |
+
|
| 84 |
+
with st.sidebar:
|
| 85 |
+
st.header("👇 Enter your trip details")
|
| 86 |
+
with st.form("my_form"):
|
| 87 |
+
location = st.text_input(
|
| 88 |
+
"Where are you currently located?", placeholder="San Mateo, CA")
|
| 89 |
+
cities = st.text_input(
|
| 90 |
+
"City and country are you interested in vacationing at?", placeholder="Bali, Indonesia")
|
| 91 |
+
date_range = st.date_input(
|
| 92 |
+
"Date range you are interested in traveling?",
|
| 93 |
+
min_value=today,
|
| 94 |
+
value=(today, jan_16_next_year + datetime.timedelta(days=6)),
|
| 95 |
+
format="MM/DD/YYYY",
|
| 96 |
+
)
|
| 97 |
+
interests = st.text_area("High level interests and hobbies or extra details about your trip?",
|
| 98 |
+
placeholder="2 adults who love swimming, dancing, hiking, and eating")
|
| 99 |
+
|
| 100 |
+
submitted = st.form_submit_button("Submit")
|
| 101 |
+
|
| 102 |
+
st.divider()
|
| 103 |
+
|
| 104 |
+
# Credits to joaomdmoura/CrewAI for the code: https://github.com/joaomdmoura/crewAI
|
| 105 |
+
st.sidebar.markdown(
|
| 106 |
+
"""
|
| 107 |
+
Credits to [**@joaomdmoura**](https://twitter.com/joaomdmoura)
|
| 108 |
+
for creating **crewAI** 🚀
|
| 109 |
+
""",
|
| 110 |
+
unsafe_allow_html=True
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
st.sidebar.info("Click the logo to visit GitHub repo", icon="👇")
|
| 114 |
+
st.sidebar.markdown(
|
| 115 |
+
"""
|
| 116 |
+
<a href="https://github.com/joaomdmoura/crewAI" target="_blank">
|
| 117 |
+
<img src="https://raw.githubusercontent.com/joaomdmoura/crewAI/main/docs/crewai_logo.png" alt="CrewAI Logo" style="width:100px;"/>
|
| 118 |
+
</a>
|
| 119 |
+
""",
|
| 120 |
+
unsafe_allow_html=True
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
if submitted:
|
| 125 |
+
with st.status("🤖 **Agents at work...**", state="running", expanded=True) as status:
|
| 126 |
+
with st.container(height=500, border=False):
|
| 127 |
+
sys.stdout = StreamToExpander(st)
|
| 128 |
+
trip_crew = TripCrew(location, cities, date_range, interests)
|
| 129 |
+
result = trip_crew.run()
|
| 130 |
+
status.update(label="✅ Trip Plan Ready!",
|
| 131 |
+
state="complete", expanded=False)
|
| 132 |
+
|
| 133 |
+
st.subheader("Here is your Trip Plan", anchor=False, divider="rainbow")
|
| 134 |
+
st.markdown(result)
|
tools/__init__.py
ADDED
|
File without changes
|
tools/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (185 Bytes). View file
|
|
|
tools/__pycache__/browser_tools.cpython-311.pyc
ADDED
|
Binary file (3.17 kB). View file
|
|
|
tools/__pycache__/calculator_tools.cpython-311.pyc
ADDED
|
Binary file (977 Bytes). View file
|
|
|
tools/__pycache__/search_tools.cpython-311.pyc
ADDED
|
Binary file (2.17 kB). View file
|
|
|
tools/browser_tools.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
|
| 3 |
+
import requests
|
| 4 |
+
import streamlit as st
|
| 5 |
+
from crewai import Agent, Task
|
| 6 |
+
from langchain.tools import tool
|
| 7 |
+
from unstructured.partition.html import partition_html
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class BrowserTools():
|
| 11 |
+
|
| 12 |
+
@tool("Scrape website content")
|
| 13 |
+
def scrape_and_summarize_website(website):
|
| 14 |
+
"""Useful to scrape and summarize a website content"""
|
| 15 |
+
url = f"https://chrome.browserless.io/content?token={st.secrets['BROWSERLESS_API_KEY']}"
|
| 16 |
+
payload = json.dumps({"url": website})
|
| 17 |
+
headers = {'cache-control': 'no-cache', 'content-type': 'application/json'}
|
| 18 |
+
response = requests.request("POST", url, headers=headers, data=payload)
|
| 19 |
+
elements = partition_html(text=response.text)
|
| 20 |
+
content = "\n\n".join([str(el) for el in elements])
|
| 21 |
+
content = [content[i:i + 8000] for i in range(0, len(content), 8000)]
|
| 22 |
+
summaries = []
|
| 23 |
+
for chunk in content:
|
| 24 |
+
agent = Agent(
|
| 25 |
+
role='Principal Researcher',
|
| 26 |
+
goal=
|
| 27 |
+
'Do amazing researches and summaries based on the content you are working with',
|
| 28 |
+
backstory=
|
| 29 |
+
"You're a Principal Researcher at a big company and you need to do a research about a given topic.",
|
| 30 |
+
allow_delegation=False)
|
| 31 |
+
task = Task(
|
| 32 |
+
agent=agent,
|
| 33 |
+
description=
|
| 34 |
+
f'Analyze and summarize the content bellow, make sure to include the most relevant information in the summary, return only the summary nothing else.\n\nCONTENT\n----------\n{chunk}'
|
| 35 |
+
)
|
| 36 |
+
summary = task.execute()
|
| 37 |
+
summaries.append(summary)
|
| 38 |
+
return "\n\n".join(summaries)
|
tools/calculator_tools.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain.tools import tool
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class CalculatorTools():
|
| 5 |
+
|
| 6 |
+
@tool("Make a calcualtion")
|
| 7 |
+
def calculate(operation):
|
| 8 |
+
"""Useful to perform any mathematical calculations,
|
| 9 |
+
like sum, minus, multiplication, division, etc.
|
| 10 |
+
The input to this tool should be a mathematical
|
| 11 |
+
expression, a couple examples are `200*7` or `5000/2*10`
|
| 12 |
+
"""
|
| 13 |
+
return eval(operation)
|
tools/search_tools.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
|
| 3 |
+
import requests
|
| 4 |
+
import streamlit as st
|
| 5 |
+
from langchain.tools import tool
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class SearchTools():
|
| 9 |
+
|
| 10 |
+
@tool("Search the internet")
|
| 11 |
+
def search_internet(query):
|
| 12 |
+
"""Useful to search the internet
|
| 13 |
+
about a a given topic and return relevant results"""
|
| 14 |
+
top_result_to_return = 4
|
| 15 |
+
url = "https://google.serper.dev/search"
|
| 16 |
+
payload = json.dumps({"q": query})
|
| 17 |
+
headers = {
|
| 18 |
+
'X-API-KEY': st.secrets['SERPER_API_KEY'],
|
| 19 |
+
'content-type': 'application/json'
|
| 20 |
+
}
|
| 21 |
+
response = requests.request("POST", url, headers=headers, data=payload)
|
| 22 |
+
# check if there is an organic key
|
| 23 |
+
if 'organic' not in response.json():
|
| 24 |
+
return "Sorry, I couldn't find anything about that, there could be an error with you serper api key."
|
| 25 |
+
else:
|
| 26 |
+
results = response.json()['organic']
|
| 27 |
+
string = []
|
| 28 |
+
for result in results[:top_result_to_return]:
|
| 29 |
+
try:
|
| 30 |
+
string.append('\n'.join([
|
| 31 |
+
f"Title: {result['title']}", f"Link: {result['link']}",
|
| 32 |
+
f"Snippet: {result['snippet']}", "\n-----------------"
|
| 33 |
+
]))
|
| 34 |
+
except KeyError:
|
| 35 |
+
next
|
| 36 |
+
|
| 37 |
+
return '\n'.join(string)
|
trip_agents.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Agent
|
| 2 |
+
import re
|
| 3 |
+
import streamlit as st
|
| 4 |
+
from langchain_community.llms import OpenAI
|
| 5 |
+
|
| 6 |
+
from tools.browser_tools import BrowserTools
|
| 7 |
+
from tools.calculator_tools import CalculatorTools
|
| 8 |
+
from tools.search_tools import SearchTools
|
| 9 |
+
|
| 10 |
+
## My initial parsing code using callback handler to print to app
|
| 11 |
+
# def streamlit_callback(step_output):
|
| 12 |
+
# # This function will be called after each step of the agent's execution
|
| 13 |
+
# st.markdown("---")
|
| 14 |
+
# for step in step_output:
|
| 15 |
+
# if isinstance(step, tuple) and len(step) == 2:
|
| 16 |
+
# action, observation = step
|
| 17 |
+
# if isinstance(action, dict) and "tool" in action and "tool_input" in action and "log" in action:
|
| 18 |
+
# st.markdown(f"# Action")
|
| 19 |
+
# st.markdown(f"**Tool:** {action['tool']}")
|
| 20 |
+
# st.markdown(f"**Tool Input** {action['tool_input']}")
|
| 21 |
+
# st.markdown(f"**Log:** {action['log']}")
|
| 22 |
+
# st.markdown(f"**Action:** {action['Action']}")
|
| 23 |
+
# st.markdown(
|
| 24 |
+
# f"**Action Input:** ```json\n{action['tool_input']}\n```")
|
| 25 |
+
# elif isinstance(action, str):
|
| 26 |
+
# st.markdown(f"**Action:** {action}")
|
| 27 |
+
# else:
|
| 28 |
+
# st.markdown(f"**Action:** {str(action)}")
|
| 29 |
+
|
| 30 |
+
# st.markdown(f"**Observation**")
|
| 31 |
+
# if isinstance(observation, str):
|
| 32 |
+
# observation_lines = observation.split('\n')
|
| 33 |
+
# for line in observation_lines:
|
| 34 |
+
# if line.startswith('Title: '):
|
| 35 |
+
# st.markdown(f"**Title:** {line[7:]}")
|
| 36 |
+
# elif line.startswith('Link: '):
|
| 37 |
+
# st.markdown(f"**Link:** {line[6:]}")
|
| 38 |
+
# elif line.startswith('Snippet: '):
|
| 39 |
+
# st.markdown(f"**Snippet:** {line[9:]}")
|
| 40 |
+
# elif line.startswith('-'):
|
| 41 |
+
# st.markdown(line)
|
| 42 |
+
# else:
|
| 43 |
+
# st.markdown(line)
|
| 44 |
+
# else:
|
| 45 |
+
# st.markdown(str(observation))
|
| 46 |
+
# else:
|
| 47 |
+
# st.markdown(step)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class TripAgents():
|
| 51 |
+
|
| 52 |
+
def city_selection_agent(self):
|
| 53 |
+
return Agent(
|
| 54 |
+
role='City Selection Expert',
|
| 55 |
+
goal='Select the best city based on weather, season, and prices',
|
| 56 |
+
backstory='An expert in analyzing travel data to pick ideal destinations',
|
| 57 |
+
tools=[
|
| 58 |
+
SearchTools.search_internet,
|
| 59 |
+
BrowserTools.scrape_and_summarize_website,
|
| 60 |
+
],
|
| 61 |
+
verbose=True,
|
| 62 |
+
# step_callback=streamlit_callback,
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
def local_expert(self):
|
| 66 |
+
return Agent(
|
| 67 |
+
role='Local Expert at this city',
|
| 68 |
+
goal='Provide the BEST insights about the selected city',
|
| 69 |
+
backstory="""A knowledgeable local guide with extensive information
|
| 70 |
+
about the city, it's attractions and customs""",
|
| 71 |
+
tools=[
|
| 72 |
+
SearchTools.search_internet,
|
| 73 |
+
BrowserTools.scrape_and_summarize_website,
|
| 74 |
+
],
|
| 75 |
+
verbose=True,
|
| 76 |
+
# step_callback=streamlit_callback,
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
def travel_concierge(self):
|
| 80 |
+
return Agent(
|
| 81 |
+
role='Amazing Travel Concierge',
|
| 82 |
+
goal="""Create the most amazing travel itineraries with budget and
|
| 83 |
+
packing suggestions for the city""",
|
| 84 |
+
backstory="""Specialist in travel planning and logistics with
|
| 85 |
+
decades of experience""",
|
| 86 |
+
tools=[
|
| 87 |
+
SearchTools.search_internet,
|
| 88 |
+
BrowserTools.scrape_and_summarize_website,
|
| 89 |
+
CalculatorTools.calculate,
|
| 90 |
+
],
|
| 91 |
+
verbose=True,
|
| 92 |
+
# step_callback=streamlit_callback,
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
###########################################################################################
|
| 96 |
+
# Print agent process to Streamlit app container #
|
| 97 |
+
# This portion of the code is adapted from @AbubakrChan; thank you! #
|
| 98 |
+
# https://github.com/AbubakrChan/crewai-UI-business-product-launch/blob/main/main.py#L210 #
|
| 99 |
+
###########################################################################################
|
| 100 |
+
class StreamToExpander:
|
| 101 |
+
def __init__(self, expander):
|
| 102 |
+
self.expander = expander
|
| 103 |
+
self.buffer = []
|
| 104 |
+
self.colors = ['red', 'green', 'blue', 'orange'] # Define a list of colors
|
| 105 |
+
self.color_index = 0 # Initialize color index
|
| 106 |
+
|
| 107 |
+
def write(self, data):
|
| 108 |
+
# Filter out ANSI escape codes using a regular expression
|
| 109 |
+
cleaned_data = re.sub(r'\x1B\[[0-9;]*[mK]', '', data)
|
| 110 |
+
|
| 111 |
+
# Check if the data contains 'task' information
|
| 112 |
+
task_match_object = re.search(r'\"task\"\s*:\s*\"(.*?)\"', cleaned_data, re.IGNORECASE)
|
| 113 |
+
task_match_input = re.search(r'task\s*:\s*([^\n]*)', cleaned_data, re.IGNORECASE)
|
| 114 |
+
task_value = None
|
| 115 |
+
if task_match_object:
|
| 116 |
+
task_value = task_match_object.group(1)
|
| 117 |
+
elif task_match_input:
|
| 118 |
+
task_value = task_match_input.group(1).strip()
|
| 119 |
+
|
| 120 |
+
if task_value:
|
| 121 |
+
st.toast(":robot_face: " + task_value)
|
| 122 |
+
|
| 123 |
+
# Check if the text contains the specified phrase and apply color
|
| 124 |
+
if "Entering new CrewAgentExecutor chain" in cleaned_data:
|
| 125 |
+
# Apply different color and switch color index
|
| 126 |
+
self.color_index = (self.color_index + 1) % len(self.colors) # Increment color index and wrap around if necessary
|
| 127 |
+
|
| 128 |
+
cleaned_data = cleaned_data.replace("Entering new CrewAgentExecutor chain", f":{self.colors[self.color_index]}[Entering new CrewAgentExecutor chain]")
|
| 129 |
+
|
| 130 |
+
if "City Selection Expert" in cleaned_data:
|
| 131 |
+
# Apply different color
|
| 132 |
+
cleaned_data = cleaned_data.replace("City Selection Expert", f":{self.colors[self.color_index]}[City Selection Expert]")
|
| 133 |
+
if "Local Expert at this city" in cleaned_data:
|
| 134 |
+
cleaned_data = cleaned_data.replace("Local Expert at this city", f":{self.colors[self.color_index]}[Local Expert at this city]")
|
| 135 |
+
if "Amazing Travel Concierge" in cleaned_data:
|
| 136 |
+
cleaned_data = cleaned_data.replace("Amazing Travel Concierge", f":{self.colors[self.color_index]}[Amazing Travel Concierge]")
|
| 137 |
+
if "Finished chain." in cleaned_data:
|
| 138 |
+
cleaned_data = cleaned_data.replace("Finished chain.", f":{self.colors[self.color_index]}[Finished chain.]")
|
| 139 |
+
|
| 140 |
+
self.buffer.append(cleaned_data)
|
| 141 |
+
if "\n" in data:
|
| 142 |
+
self.expander.markdown(''.join(self.buffer), unsafe_allow_html=True)
|
| 143 |
+
self.buffer = []
|
trip_tasks.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Task
|
| 2 |
+
from textwrap import dedent
|
| 3 |
+
from datetime import date
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class TripTasks():
|
| 7 |
+
|
| 8 |
+
def identify_task(self, agent, origin, cities, interests, range):
|
| 9 |
+
return Task(description=dedent(f"""
|
| 10 |
+
Analyze and select the best city for the trip based
|
| 11 |
+
on specific criteria such as weather patterns, seasonal
|
| 12 |
+
events, and travel costs. This task involves comparing
|
| 13 |
+
multiple cities, considering factors like current weather
|
| 14 |
+
conditions, upcoming cultural or seasonal events, and
|
| 15 |
+
overall travel expenses.
|
| 16 |
+
|
| 17 |
+
Your final answer must be a detailed
|
| 18 |
+
report on the chosen city, and everything you found out
|
| 19 |
+
about it, including the actual flight costs, weather
|
| 20 |
+
forecast and attractions.
|
| 21 |
+
{self.__tip_section()}
|
| 22 |
+
|
| 23 |
+
Traveling from: {origin}
|
| 24 |
+
City Options: {cities}
|
| 25 |
+
Trip Date: {range}
|
| 26 |
+
Traveler Interests: {interests}
|
| 27 |
+
"""),
|
| 28 |
+
expected_output="A detailed report on the chosen city with flight costs, weather forecast, and attractions.",
|
| 29 |
+
agent=agent)
|
| 30 |
+
|
| 31 |
+
def gather_task(self, agent, origin, interests, range):
|
| 32 |
+
return Task(description=dedent(f"""
|
| 33 |
+
As a local expert on this city you must compile an
|
| 34 |
+
in-depth guide for someone traveling there and wanting
|
| 35 |
+
to have THE BEST trip ever!
|
| 36 |
+
Gather information about key attractions, local customs,
|
| 37 |
+
special events, and daily activity recommendations.
|
| 38 |
+
Find the best spots to go to, the kind of place only a
|
| 39 |
+
local would know.
|
| 40 |
+
This guide should provide a thorough overview of what
|
| 41 |
+
the city has to offer, including hidden gems, cultural
|
| 42 |
+
hotspots, must-visit landmarks, weather forecasts, and
|
| 43 |
+
high level costs.
|
| 44 |
+
|
| 45 |
+
The final answer must be a comprehensive city guide,
|
| 46 |
+
rich in cultural insights and practical tips,
|
| 47 |
+
tailored to enhance the travel experience.
|
| 48 |
+
{self.__tip_section()}
|
| 49 |
+
|
| 50 |
+
Trip Date: {range}
|
| 51 |
+
Traveling from: {origin}
|
| 52 |
+
Traveler Interests: {interests}
|
| 53 |
+
"""),
|
| 54 |
+
expected_output="A comprehensive city guide with cultural insights and practical tips.",
|
| 55 |
+
agent=agent)
|
| 56 |
+
|
| 57 |
+
def plan_task(self, agent, origin, interests, range):
|
| 58 |
+
return Task(description=dedent(f"""
|
| 59 |
+
Expand this guide into a full travel
|
| 60 |
+
itinerary for this time {range} with detailed per-day plans, including
|
| 61 |
+
weather forecasts, places to eat, packing suggestions,
|
| 62 |
+
and a budget breakdown.
|
| 63 |
+
|
| 64 |
+
You MUST suggest actual places to visit, actual hotels
|
| 65 |
+
to stay and actual restaurants to go to.
|
| 66 |
+
|
| 67 |
+
This itinerary should cover all aspects of the trip,
|
| 68 |
+
from arrival to departure, integrating the city guide
|
| 69 |
+
information with practical travel logistics.
|
| 70 |
+
|
| 71 |
+
Your final answer MUST be a complete expanded travel plan,
|
| 72 |
+
formatted as markdown, encompassing a daily schedule,
|
| 73 |
+
anticipated weather conditions, recommended clothing and
|
| 74 |
+
items to pack, and a detailed budget, ensuring THE BEST
|
| 75 |
+
TRIP EVER, Be specific and give it a reason why you picked
|
| 76 |
+
# up each place, what make them special! {self.__tip_section()}
|
| 77 |
+
|
| 78 |
+
Trip Date: {range}
|
| 79 |
+
Traveling from: {origin}
|
| 80 |
+
Traveler Interests: {interests}
|
| 81 |
+
"""),
|
| 82 |
+
expected_output="A complete 7-day travel plan, formatted as markdown, with a daily schedule and budget.",
|
| 83 |
+
agent=agent)
|
| 84 |
+
|
| 85 |
+
def __tip_section(self):
|
| 86 |
+
return "If you do your BEST WORK, I'll tip you $100 and grant you any wish you want!"
|