ahensd commited on
Commit
9df24bd
·
verified ·
1 Parent(s): 028f5da

Upload 15 files

Browse files
.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!"