From df67b03bfa8dff31b86e9e3f457f0aa5d8e18a50 Mon Sep 17 00:00:00 2001 From: Mish Ushakov Date: Thu, 23 May 2024 17:47:11 +0300 Subject: [PATCH 1/8] added browserbase flights example --- README.md | 21 ++-- browserbase_flights/.env.example | 2 + browserbase_flights/.gitignore | 164 ++++++++++++++++++++++++++++++ browserbase_flights/README.md | 28 +++++ browserbase_flights/bb.py | 26 +++++ browserbase_flights/demo.py | 71 +++++++++++++ browserbase_flights/skyscanner.py | 19 ++++ 7 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 browserbase_flights/.env.example create mode 100644 browserbase_flights/.gitignore create mode 100644 browserbase_flights/README.md create mode 100644 browserbase_flights/bb.py create mode 100644 browserbase_flights/demo.py create mode 100644 browserbase_flights/skyscanner.py diff --git a/README.md b/README.md index 093e8a1c..d08819a8 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,17 @@ By [@joaomdmoura](https://x.com/joaomdmoura). ## Examples ### Basic Examples -- [Create Job Posting](https://github.com/joaomdmoura/crewAI-examples/tree/main/job-posting) -- [Trip Planner](https://github.com/joaomdmoura/crewAI-examples/tree/main/trip_planner) -- [Create Instagram Post](https://github.com/joaomdmoura/crewAI-examples/tree/main/instagram_post) -- [Markdown Validator](https://github.com/joaomdmoura/crewAI-examples/tree/main/markdown_validator) -- [Game Generator](https://github.com/joaomdmoura/crewAI-examples/tree/main/game-builder-crew) -- [Using Azure OpenAI API](https://github.com/joaomdmoura/crewAI-examples/tree/main/azure_model) +- [Create Job Posting](./job-posting) +- [Trip Planner](./trip_planner) +- [Create Instagram Post](./instagram_post) +- [Markdown Validator](./markdown_validator) +- [Game Generator](./game-builder-crew) +- [Using Azure OpenAI API](./azure_model) Starting your own example - - [Starter Template](https://github.com/joaomdmoura/crewAI-examples/tree/main//starter_template) + - [Starter Template](.//starter_template) ### Advanced Examples -- [Stock Analysis](https://github.com/joaomdmoura/crewAI-examples/tree/main/stock_analysis) -- [Landing Page Generator](https://github.com/joaomdmoura/crewAI-examples/tree/main/landing_page_generator) -- [CrewAI + LangGraph](https://github.com/joaomdmoura/crewAI-examples/tree/main/CrewAI-LangGraph) \ No newline at end of file +- [Stock Analysis](./stock_analysis) +- [Landing Page Generator](./landing_page_generator) +- [CrewAI + LangGraph](./CrewAI-LangGraph) +- [Browserbase](./browserbase_flights) diff --git a/browserbase_flights/.env.example b/browserbase_flights/.env.example new file mode 100644 index 00000000..9d438b33 --- /dev/null +++ b/browserbase_flights/.env.example @@ -0,0 +1,2 @@ +OPENAI_API_KEY= +BROWSERBASE_API_KEY= diff --git a/browserbase_flights/.gitignore b/browserbase_flights/.gitignore new file mode 100644 index 00000000..70776f6e --- /dev/null +++ b/browserbase_flights/.gitignore @@ -0,0 +1,164 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +.ruff_cache diff --git a/browserbase_flights/README.md b/browserbase_flights/README.md new file mode 100644 index 00000000..b19da57c --- /dev/null +++ b/browserbase_flights/README.md @@ -0,0 +1,28 @@ +# crewAI + Browserbase flight search + +The following is a multi-task, multi-agent, multi-tool example for AI-based flight search using Skyscanner and Browserbase. + +## Installation + +``` +pip install crewai 'crewai[tools]' html2text playwright +``` + +Set the required environment variables: + +``` +export OPENAI_API_KEY= +export BROWSERBASE_API_KEY= +``` + +Optionally, set a different model in CrewAI: + +``` +export OPENAI_MODEL_NAME=gpt-4-turbo +``` + +## Demo + +``` +python3 demo.py "Sofia to Berlin one-way on 26th May" +``` diff --git a/browserbase_flights/bb.py b/browserbase_flights/bb.py new file mode 100644 index 00000000..fe73f9b0 --- /dev/null +++ b/browserbase_flights/bb.py @@ -0,0 +1,26 @@ +import os +from crewai_tools import tool +from playwright.sync_api import sync_playwright +from html2text import html2text +from time import sleep + + +@tool("Browserbase tool") +def browserbase(url: str): + """ + Loads a URL using a headless webbrowser + """ + with sync_playwright() as playwright: + browser = playwright.chromium.connect_over_cdp( + "wss://connect.browserbase.com?apiKey=" + os.environ["BROWSERBASE_API_KEY"] + ) + context = browser.contexts[0] + page = context.pages[0] + page.goto(url) + + sleep(5) + + page.screenshot(path="screenshot.png") + content = html2text(page.content()) + browser.close() + return content diff --git a/browserbase_flights/demo.py b/browserbase_flights/demo.py new file mode 100644 index 00000000..0feb78d3 --- /dev/null +++ b/browserbase_flights/demo.py @@ -0,0 +1,71 @@ +import sys +from crewai import Crew, Process, Task, Agent +from bb import browserbase +from skyscanner import skyscanner + +output_search_example = """ +Here are our top 5 flights from Sofia to Berlin on 24th May 2024: + +1. Bulgaria Air: Departure: 14:45, Arrival: 15:55, Duration: 2 hours 10 minutes, Layovers: Munich, 2 hours layover, Price: £123, Flight page: https://www.skyscanner.net/transport/flights/sof/ber/240524/240526/config/16440-2405241445--32474-0-9828-2405241555|9828-2405262255--32474-0-16440-2405270205 +""" + +output_result_example = """ +Here are our top 5 flight options from Sofia to Berlin on 24th May 2024: + +1. Bulgaria Air: + - Departure: 14:45 + - Arrival: 15:55 + - Duration: 2 hours 10 minutes + - Layovers: Munich, 2 hours layover + - Price: £123 + - Booking options: + 1. [MyTrip](https://www.skyscanner.net/transport_deeplink/4.0/UK/en-GB/GBP/ctuk/1/16440.9828.2024-05-26/air/trava/flights?itinerary=flight|-32474|319|16440|2024-05-26T21:05|9828|2024-05-26T22:15|130|-|-|-&carriers=-32474&operators=-32474&passengers=1&channel=website&cabin_class=economy&fps_session_id=20287887-26ad-45dc-b225-28fb4b9d8357&ticket_price=126.90&is_npt=false&is_multipart=false&client_id=skyscanner_website&request_id=4b423165-9b7b-4281-9596-cfcd6b0bb4e0&q_ids=H4sIAAAAAAAA_-NS52JJLinNFmLh2NHAKMXM8cRHoeH7yU1sRkwKjEWsqXm67k5VzO5OAQASECl8KQAAAA|8257781087420252411|2&q_sources=JACQUARD&commercial_filters=false&q_datetime_utc=2024-05-22T13:45:58&pqid=true&booking_panel_option_guid=dfb1f593-22dc-4565-8540-5f4f70979b9b&index=0&isbp=1&posidx=0&qid=16440-2405262105--32474-0-9828-2405262215&sort=BEST&stops=0&tabs=CombinedDayView&pre_redirect_id=7cdb112a-3842-4a51-b228-1cbcbc4c8094&redirect_id=a8541976-84a8-4161-849c-c7a6343125ae&is_acorn_referral=true) +""" + +flights = Agent( + role="Flights", + goal="Search flights", + backstory="I am an agent that can search for flights.", + verbose=True, + tools=[skyscanner, browserbase], + allow_delegation=False, +) + +summarize_agent = Agent( + role="Summarize", + goal="Summarize content", + backstory="I am an agent that can summarize text.", + verbose=True, + allow_delegation=False, +) + +search_task = Task( + description=( + "Search flights according to criteria {request}. Current year: {current_year}" + ), + expected_output=output_search_example, + agent=flights, + human_input=False, # Optional +) + +search_providers = Task( + description="Load every flight individually and find available booking providers", + expected_output=output_result_example, + agent=flights, + human_input=False, +) + +crew = Crew( + agents=[flights, summarize_agent], + tasks=[search_task, search_providers], + process=Process.sequential, + memory=False, # Do i need this? + cache=True, + max_rpm=100, +) + +result = crew.kickoff( + inputs={"request": sys.argv[1], "current_year": 2024} +) + +print(result) diff --git a/browserbase_flights/skyscanner.py b/browserbase_flights/skyscanner.py new file mode 100644 index 00000000..ed4df2cd --- /dev/null +++ b/browserbase_flights/skyscanner.py @@ -0,0 +1,19 @@ +# https://www.skyscanner.net/transport/flights/sof/ber/240521 + +from crewai_tools import tool +from typing import Optional + + +@tool("SkyScanner tool") +def skyscanner( + departure: str, destination: str, date: int, return_date: Optional[int] = 0 +) -> str: + """ + Generates a SkyScanner URL for flights between departure and destination on the specified date. + + :param departure: The IATA code for the departure airport (e.g., 'sof' for Sofia) + :param destination: The IATA code for the destination airport (e.g., 'ber' for Berlin) + :param date: The date of the flight in the format 'yymmdd' + :return_date: Only for two-way tickets. The date of return flight in the format 'yymmdd' + """ + return f"https://www.skyscanner.net/transport/flights/{departure}/{destination}/{date}/{return_date}" From ac0cb890fb44a7d57cc1d077f5643cfad81d639f Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Mon, 27 May 2024 13:55:39 +0300 Subject: [PATCH 2/8] Update README.md Co-authored-by: Charly Poly <1252066+charlypoly@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d08819a8..5afbb4e2 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,4 @@ Starting your own example - [Stock Analysis](./stock_analysis) - [Landing Page Generator](./landing_page_generator) - [CrewAI + LangGraph](./CrewAI-LangGraph) -- [Browserbase](./browserbase_flights) +- [Flight Booker with Browserbase](./browserbase_flights) From 8ed704ad5c95bd5b966e509f3439f4ca5ee1eea1 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Mon, 3 Jun 2024 15:33:52 +0200 Subject: [PATCH 3/8] updated browserbase flight search demo --- README.md | 2 +- browserbase_flights/.env.example | 2 - browserbase_flights/README.md | 28 --- flight_search/.env.example | 4 + .../.gitignore | 0 flight_search/README.md | 219 ++++++++++++++++++ {browserbase_flights => flight_search}/bb.py | 11 +- .../demo.py => flight_search/main.py | 16 +- .../skyscanner.py | 5 +- 9 files changed, 244 insertions(+), 43 deletions(-) delete mode 100644 browserbase_flights/.env.example delete mode 100644 browserbase_flights/README.md create mode 100644 flight_search/.env.example rename {browserbase_flights => flight_search}/.gitignore (100%) create mode 100644 flight_search/README.md rename {browserbase_flights => flight_search}/bb.py (61%) rename browserbase_flights/demo.py => flight_search/main.py (50%) rename {browserbase_flights => flight_search}/skyscanner.py (85%) diff --git a/README.md b/README.md index 5afbb4e2..3c62f538 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,4 @@ Starting your own example - [Stock Analysis](./stock_analysis) - [Landing Page Generator](./landing_page_generator) - [CrewAI + LangGraph](./CrewAI-LangGraph) -- [Flight Booker with Browserbase](./browserbase_flights) +- [Flight Booker with Browserbase](./flight_search) diff --git a/browserbase_flights/.env.example b/browserbase_flights/.env.example deleted file mode 100644 index 9d438b33..00000000 --- a/browserbase_flights/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -OPENAI_API_KEY= -BROWSERBASE_API_KEY= diff --git a/browserbase_flights/README.md b/browserbase_flights/README.md deleted file mode 100644 index b19da57c..00000000 --- a/browserbase_flights/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# crewAI + Browserbase flight search - -The following is a multi-task, multi-agent, multi-tool example for AI-based flight search using Skyscanner and Browserbase. - -## Installation - -``` -pip install crewai 'crewai[tools]' html2text playwright -``` - -Set the required environment variables: - -``` -export OPENAI_API_KEY= -export BROWSERBASE_API_KEY= -``` - -Optionally, set a different model in CrewAI: - -``` -export OPENAI_MODEL_NAME=gpt-4-turbo -``` - -## Demo - -``` -python3 demo.py "Sofia to Berlin one-way on 26th May" -``` diff --git a/flight_search/.env.example b/flight_search/.env.example new file mode 100644 index 00000000..5bcdb8d2 --- /dev/null +++ b/flight_search/.env.example @@ -0,0 +1,4 @@ +OPENAI_API_KEY= +OPENAI_MODEL_NAME=gpt-4-turbo +BROWSERBASE_API_KEY= +BROWSERBASE_PROJECT_ID= diff --git a/browserbase_flights/.gitignore b/flight_search/.gitignore similarity index 100% rename from browserbase_flights/.gitignore rename to flight_search/.gitignore diff --git a/flight_search/README.md b/flight_search/README.md new file mode 100644 index 00000000..411f5959 --- /dev/null +++ b/flight_search/README.md @@ -0,0 +1,219 @@ +# CrewAI flight search (using Browserbase) + +The following is a multi-task, multi-agent, multi-tool example for AI-based flight search using Skyscanner and Browserbase. + +> [!TIP] +> [Browserbase](https://browserbase.com) is used to pre-render JavaScript pages, avoid IP blocks and captchas. As you will see in the example, AI-agents are especially useful for fetching content not available via APIs. + +## Installation + +### Setup + +Install the required dependencies by running the following command: + +``` +pip install crewai 'crewai[tools]' html2text playwright +``` + +Set the required environment variables: + +``` +export OPENAI_API_KEY= +export BROWSERBASE_API_KEY= +``` + +Optional, but recommended. Set a different model type in CrewAI to avoid token size limits: + +``` +export OPENAI_MODEL_NAME=gpt-4-turbo +``` + +### Running the Demo + +Start `main.py` script using Python, followed by your trip request: + +``` +python3 main.py "Sofia to Berlin one-way on 26th May" +``` + +Example output: + +``` +Here are our top 5 picks from Sofia to Berlin on 2nd July 2024: + +1. **Ryanair** + - Departure: 21:35 + - Arrival: 22:50 + - Duration: 2 hours 15 minutes + - Layovers: Direct + - Price: $18 + - Booking: [Ryanair](https://www.skyscanner.net/transport/flights/sof/ber/240702/0/config/16440-2407022135--31915-0-9828-2407022250?currency=USD) +... +``` + +## Guide + +Explaining how to reproduce the example step-by-step. + +### Agents, Tasks and Crews + +1. Import the required dependencies: + +```python +import sys +import os +from crewai import Crew, Process, Task, Agent +from crewai_tools import tool +from playwright.sync_api import sync_playwright +from html2text import html2text +from time import sleep +from typing import Optional +``` + +2. Create a flight agent for searching flights: + +```python +flights = Agent( + role="Flights", + goal="Search flights", + backstory="I am an agent that can search for flights.", + verbose=True, + tools=[skyscanner, browserbase], + allow_delegation=False, +) +``` + +2. Create a summarizer agent for summarizing outputs: + +```python +summarize_agent = Agent( + role="Summarize", + goal="Summarize content", + backstory="I am an agent that can summarize text.", + verbose=True, + allow_delegation=False, +) +``` + +3. Specify a task for searching flights according to criteria, including an output example: + +```python +output_search_example = """ +Here are our top 5 flights from Sofia to Berlin on 24th May 2024: + +1. Bulgaria Air: Departure: 14:45, Arrival: 15:55, Duration: 2 hours 10 minutes, Layovers: Munich, 2 hours layover, Price: $123, Details: https://www.skyscanner.net/transport/flights/sof/ber/240524/240526/config/16440-2405241445--32474-0-9828-2405241555|9828-2405262255--32474-0-16440-2405270205 +""" + +search_task = Task( + description=( + "Search flights according to criteria {request}. Current year: {current_year}" + ), + expected_output=output_search_example, + agent=flights, + human_input=False, # Optional +) +``` + +4. Specify a task for fetching each flight for retrieving the booking links: + +> [!TIP] +> CrewAI Agent is able to automatically loop each flight from the previous task to retrieve the booking information + +```python +output_result_example = """ +Here are our top 5 picks from Sofia to Berlin on 24th May 2024: + +1. Bulgaria Air: + - Departure: 14:45 + - Arrival: 15:55 + - Duration: 2 hours 10 minutes + - Layovers: Munich, 2 hours layover + - Price: $123 + - Booking: [MyTrip](https://www.skyscanner.net/transport_deeplink/4.0/UK/en-GB/GBP/ctuk/1/16440.9828.2024-05-26/air/trava/flights?itinerary=flight|-32474|319|16440|2024-05-26T21:05|9828|2024-05-26T22:15|130|-|-|-&carriers=-32474&operators=-32474&passengers=1&channel=website&cabin_class=economy&fps_session_id=20287887-26ad-45dc-b225-28fb4b9d8357&ticket_price=126.90&is_npt=false&is_multipart=false&client_id=skyscanner_website&request_id=4b423165-9b7b-4281-9596-cfcd6b0bb4e0&q_ids=H4sIAAAAAAAA_-NS52JJLinNFmLh2NHAKMXM8cRHoeH7yU1sRkwKjEWsqXm67k5VzO5OAQASECl8KQAAAA|8257781087420252411|2&q_sources=JACQUARD&commercial_filters=false&q_datetime_utc=2024-05-22T13:45:58&pqid=true&booking_panel_option_guid=dfb1f593-22dc-4565-8540-5f4f70979b9b&index=0&isbp=1&posidx=0&qid=16440-2405262105--32474-0-9828-2405262215&sort=BEST&stops=0&tabs=CombinedDayView&pre_redirect_id=7cdb112a-3842-4a51-b228-1cbcbc4c8094&redirect_id=a8541976-84a8-4161-849c-c7a6343125ae&is_acorn_referral=true) +""" + +search_providers = Task( + description="Load every flight individually and find available booking providers", + expected_output=output_result_example, + agent=flights, + human_input=False, +) +``` + +5. Initialize new crew with agents and tasks: + +```python +crew = Crew( + agents=[flights, summarize_agent], + tasks=[search_task, search_providers], + process=Process.sequential, + memory=False, + cache=True, + max_rpm=100, +) +``` + +6. Kick off the crew and print the result: + +```python +result = crew.kickoff( + inputs={ + "request": "Flights from Sofia to Berlin on 2th July", + "current_year": 2024, + } +) + +print(result) +``` + +### Bring up the tools + +1. Create a Skyscanner tool to generate a valid Skyscanner URL for the given query + +```python +@tool("SkyScanner tool") +def skyscanner( + departure: str, destination: str, date: int, return_date: Optional[int] = 0 +) -> str: + """ + Generates a SkyScanner URL for flights between departure and destination on the specified date. + + :param departure: The IATA code for the departure airport (e.g., 'sof' for Sofia) + :param destination: The IATA code for the destination airport (e.g., 'ber' for Berlin) + :param date: The date of the flight in the format 'yymmdd' + :return_date: Only for two-way tickets. The date of return flight in the format 'yymmdd' + :return: The SkyScanner URL for the specified flight search + """ + return f"https://www.skyscanner.net/transport/flights/{departure}/{destination}/{date}/{return_date}?currency=USD" +``` + +2. Create a browserbase tool to open webpages using a headless web browser + +```python +@tool("Browserbase tool") +def browserbase(url: str): + """ + Loads a URL using a headless webbrowser + + :param url: The URL to load + :return: The text content of the page + """ + with sync_playwright() as playwright: + browser = playwright.chromium.connect_over_cdp( + "wss://connect.browserbase.com?enableProxy=true&apiKey=" + + os.environ["BROWSERBASE_API_KEY"] + ) + context = browser.contexts[0] + page = context.pages[0] + page.goto(url) + + # Wait for async content of the page to load + sleep(5) + + # Optionally take a screenshot to debug current page + # page.screenshot(path="screenshot.png") + + content = html2text(page.content()) + browser.close() + return content +``` diff --git a/browserbase_flights/bb.py b/flight_search/bb.py similarity index 61% rename from browserbase_flights/bb.py rename to flight_search/bb.py index fe73f9b0..742f8a5c 100644 --- a/browserbase_flights/bb.py +++ b/flight_search/bb.py @@ -9,18 +9,25 @@ def browserbase(url: str): """ Loads a URL using a headless webbrowser + + :param url: The URL to load + :return: The text content of the page """ with sync_playwright() as playwright: browser = playwright.chromium.connect_over_cdp( - "wss://connect.browserbase.com?apiKey=" + os.environ["BROWSERBASE_API_KEY"] + "wss://connect.browserbase.com?enableProxy=true&apiKey=" + + os.environ["BROWSERBASE_API_KEY"] ) context = browser.contexts[0] page = context.pages[0] page.goto(url) + # Wait for async content of the page to load sleep(5) - page.screenshot(path="screenshot.png") + # Optionally take a screenshot to debug current page + # page.screenshot(path="screenshot.png") + content = html2text(page.content()) browser.close() return content diff --git a/browserbase_flights/demo.py b/flight_search/main.py similarity index 50% rename from browserbase_flights/demo.py rename to flight_search/main.py index 0feb78d3..cf198aa4 100644 --- a/browserbase_flights/demo.py +++ b/flight_search/main.py @@ -6,20 +6,19 @@ output_search_example = """ Here are our top 5 flights from Sofia to Berlin on 24th May 2024: -1. Bulgaria Air: Departure: 14:45, Arrival: 15:55, Duration: 2 hours 10 minutes, Layovers: Munich, 2 hours layover, Price: £123, Flight page: https://www.skyscanner.net/transport/flights/sof/ber/240524/240526/config/16440-2405241445--32474-0-9828-2405241555|9828-2405262255--32474-0-16440-2405270205 +1. Bulgaria Air: Departure: 14:45, Arrival: 15:55, Duration: 2 hours 10 minutes, Layovers: Munich, 2 hours layover, Price: $123, Details: https://www.skyscanner.net/transport/flights/sof/ber/240524/240526/config/16440-2405241445--32474-0-9828-2405241555|9828-2405262255--32474-0-16440-2405270205 """ output_result_example = """ -Here are our top 5 flight options from Sofia to Berlin on 24th May 2024: +Here are our top 5 picks from Sofia to Berlin on 24th May 2024: 1. Bulgaria Air: - Departure: 14:45 - Arrival: 15:55 - Duration: 2 hours 10 minutes - Layovers: Munich, 2 hours layover - - Price: £123 - - Booking options: - 1. [MyTrip](https://www.skyscanner.net/transport_deeplink/4.0/UK/en-GB/GBP/ctuk/1/16440.9828.2024-05-26/air/trava/flights?itinerary=flight|-32474|319|16440|2024-05-26T21:05|9828|2024-05-26T22:15|130|-|-|-&carriers=-32474&operators=-32474&passengers=1&channel=website&cabin_class=economy&fps_session_id=20287887-26ad-45dc-b225-28fb4b9d8357&ticket_price=126.90&is_npt=false&is_multipart=false&client_id=skyscanner_website&request_id=4b423165-9b7b-4281-9596-cfcd6b0bb4e0&q_ids=H4sIAAAAAAAA_-NS52JJLinNFmLh2NHAKMXM8cRHoeH7yU1sRkwKjEWsqXm67k5VzO5OAQASECl8KQAAAA|8257781087420252411|2&q_sources=JACQUARD&commercial_filters=false&q_datetime_utc=2024-05-22T13:45:58&pqid=true&booking_panel_option_guid=dfb1f593-22dc-4565-8540-5f4f70979b9b&index=0&isbp=1&posidx=0&qid=16440-2405262105--32474-0-9828-2405262215&sort=BEST&stops=0&tabs=CombinedDayView&pre_redirect_id=7cdb112a-3842-4a51-b228-1cbcbc4c8094&redirect_id=a8541976-84a8-4161-849c-c7a6343125ae&is_acorn_referral=true) + - Price: $123 + - Booking: [MyTrip](https://www.skyscanner.net/transport_deeplink/4.0/UK/en-GB/GBP/ctuk/1/16440.9828.2024-05-26/air/trava/flights?itinerary=flight|-32474|319|16440|2024-05-26T21:05|9828|2024-05-26T22:15|130|-|-|-&carriers=-32474&operators=-32474&passengers=1&channel=website&cabin_class=economy&fps_session_id=20287887-26ad-45dc-b225-28fb4b9d8357&ticket_price=126.90&is_npt=false&is_multipart=false&client_id=skyscanner_website&request_id=4b423165-9b7b-4281-9596-cfcd6b0bb4e0&q_ids=H4sIAAAAAAAA_-NS52JJLinNFmLh2NHAKMXM8cRHoeH7yU1sRkwKjEWsqXm67k5VzO5OAQASECl8KQAAAA|8257781087420252411|2&q_sources=JACQUARD&commercial_filters=false&q_datetime_utc=2024-05-22T13:45:58&pqid=true&booking_panel_option_guid=dfb1f593-22dc-4565-8540-5f4f70979b9b&index=0&isbp=1&posidx=0&qid=16440-2405262105--32474-0-9828-2405262215&sort=BEST&stops=0&tabs=CombinedDayView&pre_redirect_id=7cdb112a-3842-4a51-b228-1cbcbc4c8094&redirect_id=a8541976-84a8-4161-849c-c7a6343125ae&is_acorn_referral=true) """ flights = Agent( @@ -59,13 +58,16 @@ agents=[flights, summarize_agent], tasks=[search_task, search_providers], process=Process.sequential, - memory=False, # Do i need this? + memory=False, cache=True, max_rpm=100, ) result = crew.kickoff( - inputs={"request": sys.argv[1], "current_year": 2024} + inputs={ + "request": sys.argv[1] or "Flights from Sofia to Berlin on 2th July", + "current_year": 2024, + } ) print(result) diff --git a/browserbase_flights/skyscanner.py b/flight_search/skyscanner.py similarity index 85% rename from browserbase_flights/skyscanner.py rename to flight_search/skyscanner.py index ed4df2cd..ad04e399 100644 --- a/browserbase_flights/skyscanner.py +++ b/flight_search/skyscanner.py @@ -1,5 +1,3 @@ -# https://www.skyscanner.net/transport/flights/sof/ber/240521 - from crewai_tools import tool from typing import Optional @@ -15,5 +13,6 @@ def skyscanner( :param destination: The IATA code for the destination airport (e.g., 'ber' for Berlin) :param date: The date of the flight in the format 'yymmdd' :return_date: Only for two-way tickets. The date of return flight in the format 'yymmdd' + :return: The SkyScanner URL for the specified flight search """ - return f"https://www.skyscanner.net/transport/flights/{departure}/{destination}/{date}/{return_date}" + return f"https://www.skyscanner.net/transport/flights/{departure}/{destination}/{date}/{return_date}?currency=USD" From 214e297e698332171e94209ecb6847c45abaab9d Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:48:24 +0200 Subject: [PATCH 4/8] Update flight_search/main.py Co-authored-by: Charly Poly <1252066+charlypoly@users.noreply.github.com> --- flight_search/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/flight_search/main.py b/flight_search/main.py index cf198aa4..115c6d80 100644 --- a/flight_search/main.py +++ b/flight_search/main.py @@ -1,4 +1,5 @@ import sys +import datetime from crewai import Crew, Process, Task, Agent from bb import browserbase from skyscanner import skyscanner From 1bf7802a1bba42f1fe29d2a897bd3f7ed250c6b1 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:48:30 +0200 Subject: [PATCH 5/8] Update flight_search/main.py Co-authored-by: Charly Poly <1252066+charlypoly@users.noreply.github.com> --- flight_search/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight_search/main.py b/flight_search/main.py index 115c6d80..913542e7 100644 --- a/flight_search/main.py +++ b/flight_search/main.py @@ -67,7 +67,7 @@ result = crew.kickoff( inputs={ "request": sys.argv[1] or "Flights from Sofia to Berlin on 2th July", - "current_year": 2024, + "current_year": datetime.date.today().year, } ) From 7bbeb4cecaaa1ea20595a899949aee7c5cae701b Mon Sep 17 00:00:00 2001 From: Charly POLY Date: Wed, 5 Jun 2024 16:09:13 +0200 Subject: [PATCH 6/8] variable naming consistency + remove options with default values --- flight_search/README.md | 18 +++++++--------- flight_search/{bb.py => browserbase.py} | 0 flight_search/main.py | 28 ++++++++++++------------- 3 files changed, 21 insertions(+), 25 deletions(-) rename flight_search/{bb.py => browserbase.py} (100%) diff --git a/flight_search/README.md b/flight_search/README.md index 411f5959..73ced645 100644 --- a/flight_search/README.md +++ b/flight_search/README.md @@ -12,14 +12,15 @@ The following is a multi-task, multi-agent, multi-tool example for AI-based flig Install the required dependencies by running the following command: ``` -pip install crewai 'crewai[tools]' html2text playwright +pip install crewai 'crewai[tools]' html2text playwright dotenv ``` -Set the required environment variables: +Set the required environment variables in a `.env` file: ``` export OPENAI_API_KEY= export BROWSERBASE_API_KEY= +export BROWSERBASE_PROJECT_ID= ``` Optional, but recommended. Set a different model type in CrewAI to avoid token size limits: @@ -73,7 +74,7 @@ from typing import Optional 2. Create a flight agent for searching flights: ```python -flights = Agent( +flights_agent = Agent( role="Flights", goal="Search flights", backstory="I am an agent that can search for flights.", @@ -110,7 +111,6 @@ search_task = Task( ), expected_output=output_search_example, agent=flights, - human_input=False, # Optional ) ``` @@ -132,11 +132,10 @@ Here are our top 5 picks from Sofia to Berlin on 24th May 2024: - Booking: [MyTrip](https://www.skyscanner.net/transport_deeplink/4.0/UK/en-GB/GBP/ctuk/1/16440.9828.2024-05-26/air/trava/flights?itinerary=flight|-32474|319|16440|2024-05-26T21:05|9828|2024-05-26T22:15|130|-|-|-&carriers=-32474&operators=-32474&passengers=1&channel=website&cabin_class=economy&fps_session_id=20287887-26ad-45dc-b225-28fb4b9d8357&ticket_price=126.90&is_npt=false&is_multipart=false&client_id=skyscanner_website&request_id=4b423165-9b7b-4281-9596-cfcd6b0bb4e0&q_ids=H4sIAAAAAAAA_-NS52JJLinNFmLh2NHAKMXM8cRHoeH7yU1sRkwKjEWsqXm67k5VzO5OAQASECl8KQAAAA|8257781087420252411|2&q_sources=JACQUARD&commercial_filters=false&q_datetime_utc=2024-05-22T13:45:58&pqid=true&booking_panel_option_guid=dfb1f593-22dc-4565-8540-5f4f70979b9b&index=0&isbp=1&posidx=0&qid=16440-2405262105--32474-0-9828-2405262215&sort=BEST&stops=0&tabs=CombinedDayView&pre_redirect_id=7cdb112a-3842-4a51-b228-1cbcbc4c8094&redirect_id=a8541976-84a8-4161-849c-c7a6343125ae&is_acorn_referral=true) """ -search_providers = Task( +search_booking_providers_task = Task( description="Load every flight individually and find available booking providers", expected_output=output_result_example, agent=flights, - human_input=False, ) ``` @@ -144,11 +143,8 @@ search_providers = Task( ```python crew = Crew( - agents=[flights, summarize_agent], - tasks=[search_task, search_providers], - process=Process.sequential, - memory=False, - cache=True, + agents=[flights_agent, summarize_agent], + tasks=[search_task, search_booking_providers_task], max_rpm=100, ) ``` diff --git a/flight_search/bb.py b/flight_search/browserbase.py similarity index 100% rename from flight_search/bb.py rename to flight_search/browserbase.py diff --git a/flight_search/main.py b/flight_search/main.py index 913542e7..041a3002 100644 --- a/flight_search/main.py +++ b/flight_search/main.py @@ -1,8 +1,11 @@ import sys import datetime -from crewai import Crew, Process, Task, Agent -from bb import browserbase +from crewai import Crew, Task, Agent +from browserbase import browserbase from skyscanner import skyscanner +from dotenv import load_dotenv + +load_dotenv() # take environment variables from .env. output_search_example = """ Here are our top 5 flights from Sofia to Berlin on 24th May 2024: @@ -22,7 +25,7 @@ - Booking: [MyTrip](https://www.skyscanner.net/transport_deeplink/4.0/UK/en-GB/GBP/ctuk/1/16440.9828.2024-05-26/air/trava/flights?itinerary=flight|-32474|319|16440|2024-05-26T21:05|9828|2024-05-26T22:15|130|-|-|-&carriers=-32474&operators=-32474&passengers=1&channel=website&cabin_class=economy&fps_session_id=20287887-26ad-45dc-b225-28fb4b9d8357&ticket_price=126.90&is_npt=false&is_multipart=false&client_id=skyscanner_website&request_id=4b423165-9b7b-4281-9596-cfcd6b0bb4e0&q_ids=H4sIAAAAAAAA_-NS52JJLinNFmLh2NHAKMXM8cRHoeH7yU1sRkwKjEWsqXm67k5VzO5OAQASECl8KQAAAA|8257781087420252411|2&q_sources=JACQUARD&commercial_filters=false&q_datetime_utc=2024-05-22T13:45:58&pqid=true&booking_panel_option_guid=dfb1f593-22dc-4565-8540-5f4f70979b9b&index=0&isbp=1&posidx=0&qid=16440-2405262105--32474-0-9828-2405262215&sort=BEST&stops=0&tabs=CombinedDayView&pre_redirect_id=7cdb112a-3842-4a51-b228-1cbcbc4c8094&redirect_id=a8541976-84a8-4161-849c-c7a6343125ae&is_acorn_referral=true) """ -flights = Agent( +flights_agent = Agent( role="Flights", goal="Search flights", backstory="I am an agent that can search for flights.", @@ -39,34 +42,31 @@ allow_delegation=False, ) -search_task = Task( +search_flights_task = Task( description=( "Search flights according to criteria {request}. Current year: {current_year}" ), expected_output=output_search_example, - agent=flights, - human_input=False, # Optional + agent=flights_agent, ) -search_providers = Task( +search_booking_providers_task = Task( description="Load every flight individually and find available booking providers", expected_output=output_result_example, - agent=flights, + agent=flights_agent, human_input=False, ) crew = Crew( - agents=[flights, summarize_agent], - tasks=[search_task, search_providers], - process=Process.sequential, - memory=False, - cache=True, + agents=[flights_agent, summarize_agent], + tasks=[search_flights_task, search_booking_providers_task], max_rpm=100, + verbose=True ) result = crew.kickoff( inputs={ - "request": sys.argv[1] or "Flights from Sofia to Berlin on 2th July", + "request": sys.argv[1], "current_year": datetime.date.today().year, } ) From 572ac2a75b6e5b53dd40ea5697ab687d94f6876f Mon Sep 17 00:00:00 2001 From: Charly Poly <1252066+charlypoly@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:23:37 +0200 Subject: [PATCH 7/8] Update flight_search/README.md --- flight_search/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flight_search/README.md b/flight_search/README.md index 73ced645..eeaaeeb8 100644 --- a/flight_search/README.md +++ b/flight_search/README.md @@ -18,9 +18,9 @@ pip install crewai 'crewai[tools]' html2text playwright dotenv Set the required environment variables in a `.env` file: ``` -export OPENAI_API_KEY= -export BROWSERBASE_API_KEY= -export BROWSERBASE_PROJECT_ID= +OPENAI_API_KEY= +BROWSERBASE_API_KEY= +BROWSERBASE_PROJECT_ID= ``` Optional, but recommended. Set a different model type in CrewAI to avoid token size limits: From 0fdc61118434d82a2f5652f669ca57d96c41bcee Mon Sep 17 00:00:00 2001 From: Charly Poly <1252066+charlypoly@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:26:28 +0200 Subject: [PATCH 8/8] Apply suggestions from code review --- flight_search/.env.example | 1 - flight_search/README.md | 5 ----- 2 files changed, 6 deletions(-) diff --git a/flight_search/.env.example b/flight_search/.env.example index 5bcdb8d2..43627c7d 100644 --- a/flight_search/.env.example +++ b/flight_search/.env.example @@ -1,4 +1,3 @@ OPENAI_API_KEY= -OPENAI_MODEL_NAME=gpt-4-turbo BROWSERBASE_API_KEY= BROWSERBASE_PROJECT_ID= diff --git a/flight_search/README.md b/flight_search/README.md index eeaaeeb8..a5b874e1 100644 --- a/flight_search/README.md +++ b/flight_search/README.md @@ -23,11 +23,6 @@ BROWSERBASE_API_KEY= BROWSERBASE_PROJECT_ID= ``` -Optional, but recommended. Set a different model type in CrewAI to avoid token size limits: - -``` -export OPENAI_MODEL_NAME=gpt-4-turbo -``` ### Running the Demo