From a51a7000c5e84c9612f33e5d7fc378b1efdc033a Mon Sep 17 00:00:00 2001 From: rafaelsideguide <150964962+rafaelsideguide@users.noreply.github.com> Date: Thu, 16 May 2024 11:20:36 -0300 Subject: [PATCH 01/62] added Firecrawl tools --- .../firecrawl_crawl_website_tool/README.md | 42 +++++++++++++++++++ .../firecrawl_crawl_website_tool.py | 33 +++++++++++++++ .../firecrawl_scrape_website_tool/README.md | 38 +++++++++++++++++ .../firecrawl_scrape_website_tool.py | 35 ++++++++++++++++ .../tools/firecrawl_search_tool/README.md | 35 ++++++++++++++++ .../firecrawl_search_tool.py | 33 +++++++++++++++ 6 files changed, 216 insertions(+) create mode 100644 src/crewai_tools/tools/firecrawl_crawl_website_tool/README.md create mode 100644 src/crewai_tools/tools/firecrawl_crawl_website_tool/firecrawl_crawl_website_tool.py create mode 100644 src/crewai_tools/tools/firecrawl_scrape_website_tool/README.md create mode 100644 src/crewai_tools/tools/firecrawl_scrape_website_tool/firecrawl_scrape_website_tool.py create mode 100644 src/crewai_tools/tools/firecrawl_search_tool/README.md create mode 100644 src/crewai_tools/tools/firecrawl_search_tool/firecrawl_search_tool.py diff --git a/src/crewai_tools/tools/firecrawl_crawl_website_tool/README.md b/src/crewai_tools/tools/firecrawl_crawl_website_tool/README.md new file mode 100644 index 000000000..46d011602 --- /dev/null +++ b/src/crewai_tools/tools/firecrawl_crawl_website_tool/README.md @@ -0,0 +1,42 @@ +# FirecrawlCrawlWebsiteTool + +## Description + +[Firecrawl](https://firecrawl.dev) is a platform for crawling and convert any website into clean markdown or structured data. + +## Installation + +- Get an API key from [firecrawl.dev](https://firecrawl.dev) and set it in environment variables (`FIRECRAWL_API_KEY`). +- Install the [Firecrawl SDK](https://github.com/mendableai/firecrawl) along with `crewai[tools]` package: + +``` +pip install firecrawl-py 'crewai[tools]' +``` + +## Example + +Utilize the FirecrawlScrapeFromWebsiteTool as follows to allow your agent to load websites: + +```python +from crewai_tools import FirecrawlCrawlWebsiteTool + +tool = FirecrawlCrawlWebsiteTool(url='firecrawl.dev') +``` + +## Arguments + +- `api_key`: Optional. Specifies Firecrawl API key. Defaults is the `FIRECRAWL_API_KEY` environment variable. +- `url`: The base URL to start crawling from. +- `page_options`: Optional. + - `onlyMainContent`: Optional. Only return the main content of the page excluding headers, navs, footers, etc. + - `includeHtml`: Optional. Include the raw HTML content of the page. Will output a html key in the response. +- `crawler_options`: Optional. Options for controlling the crawling behavior. + - `includes`: Optional. URL patterns to include in the crawl. + - `exclude`: Optional. URL patterns to exclude from the crawl. + - `generateImgAltText`: Optional. Generate alt text for images using LLMs (requires a paid plan). + - `returnOnlyUrls`: Optional. If true, returns only the URLs as a list in the crawl status. Note: the response will be a list of URLs inside the data, not a list of documents. + - `maxDepth`: Optional. Maximum depth to crawl. Depth 1 is the base URL, depth 2 includes the base URL and its direct children, and so on. + - `mode`: Optional. The crawling mode to use. Fast mode crawls 4x faster on websites without a sitemap but may not be as accurate and shouldn't be used on heavily JavaScript-rendered websites. + - `limit`: Optional. Maximum number of pages to crawl. + - `timeout`: Optional. Timeout in milliseconds for the crawling operation. + diff --git a/src/crewai_tools/tools/firecrawl_crawl_website_tool/firecrawl_crawl_website_tool.py b/src/crewai_tools/tools/firecrawl_crawl_website_tool/firecrawl_crawl_website_tool.py new file mode 100644 index 000000000..5c796189a --- /dev/null +++ b/src/crewai_tools/tools/firecrawl_crawl_website_tool/firecrawl_crawl_website_tool.py @@ -0,0 +1,33 @@ +from typing import Optional, Any, Type, Dict, List +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class FirecrawlCrawlWebsiteToolSchema(BaseModel): + url: str = Field(description="Website URL") + crawler_options: Optional[Dict[str, Any]] = Field(default=None, description="Options for crawling") + page_options: Optional[Dict[str, Any]] = Field(default=None, description="Options for page") + +class FirecrawlCrawlWebsiteTool(BaseTool): + name: str = "Firecrawl web crawl tool" + description: str = "Crawl webpages using Firecrawl and return the contents" + args_schema: Type[BaseModel] = FirecrawlCrawlWebsiteToolSchema + api_key: Optional[str] = None + firecrawl: Optional[Any] = None + + def __init__(self, api_key: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + try: + from firecrawl import FirecrawlApp # type: ignore + except ImportError: + raise ImportError( + "`firecrawl` package not found, please run `pip install firecrawl-py`" + ) + + self.firecrawl = FirecrawlApp(api_key=api_key) + + def _run(self, url: str, crawler_options: Optional[Dict[str, Any]] = None, page_options: Optional[Dict[str, Any]] = None): + options = { + "crawlerOptions": crawler_options, + "pageOptions": page_options + } + return self.firecrawl.crawl_url(url, options) \ No newline at end of file diff --git a/src/crewai_tools/tools/firecrawl_scrape_website_tool/README.md b/src/crewai_tools/tools/firecrawl_scrape_website_tool/README.md new file mode 100644 index 000000000..93570f06b --- /dev/null +++ b/src/crewai_tools/tools/firecrawl_scrape_website_tool/README.md @@ -0,0 +1,38 @@ +# FirecrawlScrapeWebsiteTool + +## Description + +[Firecrawl](https://firecrawl.dev) is a platform for crawling and convert any website into clean markdown or structured data. + +## Installation + +- Get an API key from [firecrawl.dev](https://firecrawl.dev) and set it in environment variables (`FIRECRAWL_API_KEY`). +- Install the [Firecrawl SDK](https://github.com/mendableai/firecrawl) along with `crewai[tools]` package: + +``` +pip install firecrawl-py 'crewai[tools]' +``` + +## Example + +Utilize the FirecrawlScrapeWebsiteTool as follows to allow your agent to load websites: + +```python +from crewai_tools import FirecrawlScrapeWebsiteTool + +tool = FirecrawlScrapeWebsiteTool(url='firecrawl.dev') +``` + +## Arguments + +- `api_key`: Optional. Specifies Firecrawl API key. Defaults is the `FIRECRAWL_API_KEY` environment variable. +- `url`: The URL to scrape. +- `page_options`: Optional. + - `onlyMainContent`: Optional. Only return the main content of the page excluding headers, navs, footers, etc. + - `includeHtml`: Optional. Include the raw HTML content of the page. Will output a html key in the response. +- `extractor_options`: Optional. Options for LLM-based extraction of structured information from the page content + - `mode`: The extraction mode to use, currently supports 'llm-extraction' + - `extractionPrompt`: Optional. A prompt describing what information to extract from the page + - `extractionSchema`: Optional. The schema for the data to be extracted +- `timeout`: Optional. Timeout in milliseconds for the request + diff --git a/src/crewai_tools/tools/firecrawl_scrape_website_tool/firecrawl_scrape_website_tool.py b/src/crewai_tools/tools/firecrawl_scrape_website_tool/firecrawl_scrape_website_tool.py new file mode 100644 index 000000000..8540b13ff --- /dev/null +++ b/src/crewai_tools/tools/firecrawl_scrape_website_tool/firecrawl_scrape_website_tool.py @@ -0,0 +1,35 @@ +from typing import Optional, Any, Type, Dict +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class FirecrawlScrapeWebsiteToolSchema(BaseModel): + url: str = Field(description="Website URL") + page_options: Optional[Dict[str, Any]] = Field(default=None, description="Options for page scraping") + extractor_options: Optional[Dict[str, Any]] = Field(default=None, description="Options for data extraction") + timeout: Optional[int] = Field(default=None, description="Timeout for the scraping operation") + +class FirecrawlScrapeWebsiteTool(BaseTool): + name: str = "Firecrawl web scrape tool" + description: str = "Scrape webpages url using Firecrawl and return the contents" + args_schema: Type[BaseModel] = FirecrawlScrapeWebsiteToolSchema + api_key: Optional[str] = None + firecrawl: Optional[Any] = None + + def __init__(self, api_key: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + try: + from firecrawl import FirecrawlApp # type: ignore + except ImportError: + raise ImportError( + "`firecrawl` package not found, please run `pip install firecrawl-py`" + ) + + self.firecrawl = FirecrawlApp(api_key=api_key) + + def _run(self, url: str, page_options: Optional[Dict[str, Any]] = None, extractor_options: Optional[Dict[str, Any]] = None, timeout: Optional[int] = None): + options = { + "pageOptions": page_options, + "extractorOptions": extractor_options, + "timeout": timeout + } + return self.firecrawl.scrape_url(url, options) \ No newline at end of file diff --git a/src/crewai_tools/tools/firecrawl_search_tool/README.md b/src/crewai_tools/tools/firecrawl_search_tool/README.md new file mode 100644 index 000000000..effb3f3d4 --- /dev/null +++ b/src/crewai_tools/tools/firecrawl_search_tool/README.md @@ -0,0 +1,35 @@ +# FirecrawlSearchTool + +## Description + +[Firecrawl](https://firecrawl.dev) is a platform for crawling and convert any website into clean markdown or structured data. + +## Installation + +- Get an API key from [firecrawl.dev](https://firecrawl.dev) and set it in environment variables (`FIRECRAWL_API_KEY`). +- Install the [Firecrawl SDK](https://github.com/mendableai/firecrawl) along with `crewai[tools]` package: + +``` +pip install firecrawl-py 'crewai[tools]' +``` + +## Example + +Utilize the FirecrawlSearchTool as follows to allow your agent to load websites: + +```python +from crewai_tools import FirecrawlSearchTool + +tool = FirecrawlSearchTool(query='what is firecrawl?') +``` + +## Arguments + +- `api_key`: Optional. Specifies Firecrawl API key. Defaults is the `FIRECRAWL_API_KEY` environment variable. +- `query`: The search query string to be used for searching. +- `page_options`: Optional. Options for result formatting. + - `onlyMainContent`: Optional. Only return the main content of the page excluding headers, navs, footers, etc. + - `includeHtml`: Optional. Include the raw HTML content of the page. Will output a html key in the response. + - `fetchPageContent`: Optional. Fetch the full content of the page. +- `search_options`: Optional. Options for controlling the crawling behavior. + - `limit`: Optional. Maximum number of pages to crawl. \ No newline at end of file diff --git a/src/crewai_tools/tools/firecrawl_search_tool/firecrawl_search_tool.py b/src/crewai_tools/tools/firecrawl_search_tool/firecrawl_search_tool.py new file mode 100644 index 000000000..89843f797 --- /dev/null +++ b/src/crewai_tools/tools/firecrawl_search_tool/firecrawl_search_tool.py @@ -0,0 +1,33 @@ +from typing import Optional, Any, Type, Dict, List +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class FirecrawlSearchToolSchema(BaseModel): + query: str = Field(description="Search query") + page_options: Optional[Dict[str, Any]] = Field(default=None, description="Options for result formatting") + search_options: Optional[Dict[str, Any]] = Field(default=None, description="Options for searching") + +class FirecrawlSearchTool(BaseTool): + name: str = "Firecrawl web search tool" + description: str = "Search webpages using Firecrawl and return the results" + args_schema: Type[BaseModel] = FirecrawlSearchToolSchema + api_key: Optional[str] = None + firecrawl: Optional[Any] = None + + def __init__(self, api_key: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + try: + from firecrawl import FirecrawlApp # type: ignore + except ImportError: + raise ImportError( + "`firecrawl` package not found, please run `pip install firecrawl-py`" + ) + + self.firecrawl = FirecrawlApp(api_key=api_key) + + def _run(self, query: str, page_options: Optional[Dict[str, Any]] = None, result_options: Optional[Dict[str, Any]] = None): + options = { + "pageOptions": page_options, + "resultOptions": result_options + } + return self.firecrawl.search(query, options) From 5c2d8c4cfa86debc8f769cc9a8838a21ae1a4f72 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Mon, 20 May 2024 08:58:25 +0000 Subject: [PATCH 02/62] updated browserbase tool --- .../browserbase_load_tool.py | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/crewai_tools/tools/browserbase_load_tool/browserbase_load_tool.py b/src/crewai_tools/tools/browserbase_load_tool/browserbase_load_tool.py index 48f3dacef..52722520d 100644 --- a/src/crewai_tools/tools/browserbase_load_tool/browserbase_load_tool.py +++ b/src/crewai_tools/tools/browserbase_load_tool/browserbase_load_tool.py @@ -10,20 +10,35 @@ class BrowserbaseLoadTool(BaseTool): description: str = "Load webpages url in a headless browser using Browserbase and return the contents" args_schema: Type[BaseModel] = BrowserbaseLoadToolSchema api_key: Optional[str] = None + project_id: Optional[str] = None text_content: Optional[bool] = False + session_id: Optional[str] = None + proxy: Optional[bool] = None browserbase: Optional[Any] = None - def __init__(self, api_key: Optional[str] = None, text_content: Optional[bool] = False, **kwargs): + def __init__( + self, + api_key: Optional[str] = None, + project_id: Optional[str] = None, + text_content: Optional[bool] = False, + session_id: Optional[str] = None, + proxy: Optional[bool] = None, + **kwargs, + ): super().__init__(**kwargs) try: - from browserbase import Browserbase # type: ignore + from browserbase import Browserbase # type: ignore except ImportError: - raise ImportError( - "`browserbase` package not found, please run `pip install browserbase`" - ) + raise ImportError( + "`browserbase` package not found, please run `pip install browserbase`" + ) - self.browserbase = Browserbase(api_key=api_key) + self.browserbase = Browserbase(api_key, project_id) self.text_content = text_content + self.session_id = session_id + self.proxy = proxy def _run(self, url: str): - return self.browserbase.load_url(url, text_content=self.text_content) + return self.browserbase.load_url( + url, self.text_content, self.session_id, self.proxy + ) From bedbac2aafb80b3369abd88bd45dcdbdb67a59b0 Mon Sep 17 00:00:00 2001 From: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Date: Mon, 20 May 2024 09:02:55 +0000 Subject: [PATCH 03/62] updated browserbase tool readme --- .../tools/browserbase_load_tool/README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/crewai_tools/tools/browserbase_load_tool/README.md b/src/crewai_tools/tools/browserbase_load_tool/README.md index a2866f9a8..bd562da0d 100644 --- a/src/crewai_tools/tools/browserbase_load_tool/README.md +++ b/src/crewai_tools/tools/browserbase_load_tool/README.md @@ -2,11 +2,17 @@ ## Description -[Browserbase](https://browserbase.com) is a serverless platform for running headless browsers, it offers advanced debugging, session recordings, stealth mode, integrated proxies and captcha solving. +[Browserbase](https://browserbase.com) is a developer platform to reliably run, manage, and monitor headless browsers. + + Power your AI data retrievals with: + - [Serverless Infrastructure](https://docs.browserbase.com/under-the-hood) providing reliable browsers to extract data from complex UIs + - [Stealth Mode](https://docs.browserbase.com/features/stealth-mode) with included fingerprinting tactics and automatic captcha solving + - [Session Debugger](https://docs.browserbase.com/features/sessions) to inspect your Browser Session with networks timeline and logs + - [Live Debug](https://docs.browserbase.com/guides/session-debug-connection/browser-remote-control) to quickly debug your automation ## Installation -- Get an API key from [browserbase.com](https://browserbase.com) and set it in environment variables (`BROWSERBASE_API_KEY`). +- Get an API key and Project ID from [browserbase.com](https://browserbase.com) and set it in environment variables (`BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`). - Install the [Browserbase SDK](http://github.com/browserbase/python-sdk) along with `crewai[tools]` package: ``` @@ -25,5 +31,8 @@ tool = BrowserbaseLoadTool() ## Arguments -- `api_key`: Optional. Specifies Browserbase API key. Defaults is the `BROWSERBASE_API_KEY` environment variable. -- `text_content`: Optional. Load pages as readable text. Default is `False`. +- `api_key` Optional. Browserbase API key. Default is `BROWSERBASE_API_KEY` env variable. +- `project_id` Optional. Browserbase Project ID. Default is `BROWSERBASE_PROJECT_ID` env variable. +- `text_content` Retrieve only text content. Default is `False`. +- `session_id` Optional. Provide an existing Session ID. +- `proxy` Optional. Enable/Disable Proxies." From 4e1425665c673badcc0a233cca03733ec35656e4 Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Tue, 21 May 2024 11:48:52 +0200 Subject: [PATCH 04/62] spider tool --- .../tools/spider_crawl_tool/README.md | 27 ++++++++++++ .../tools/spider_crawl_tool/spider_tool.py | 44 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/crewai_tools/tools/spider_crawl_tool/README.md create mode 100644 src/crewai_tools/tools/spider_crawl_tool/spider_tool.py diff --git a/src/crewai_tools/tools/spider_crawl_tool/README.md b/src/crewai_tools/tools/spider_crawl_tool/README.md new file mode 100644 index 000000000..3207efcca --- /dev/null +++ b/src/crewai_tools/tools/spider_crawl_tool/README.md @@ -0,0 +1,27 @@ +# SpiderTool + +## Description + +[Spider](https://spider.cloud) is the [fastest]([Spider](https://spider.cloud/?ref=crewai) is the [fastest](https://github.com/spider-rs/spider/blob/main/benches/BENCHMARKS.md#benchmark-results) open source scraper and crawler that returns LLM-ready data. It converts any website into pure HTML, markdown, metadata or text while enabling you to crawl with custom actions using AI. + +## Installation + +To use the Spider API you need to download the [Spider SDK](https://pypi.org/project/spider-client/) and the crewai[tools] SDK too: + +```python +pip install spider-client 'crewai[tools]' +``` + +## Example + +This example shows you how you can use the Spider tool to enable your agent to scrape and crawl websites. The data returned from the Spider API is already LLM-ready, so no need to do any cleaning there. + +```python +from crewai_tools import SpiderTool + +tool = SpiderTool() +``` + +## Arguments + +- `api_key`: Optional. Specifies Spider API key. If not specified it looks for `SPIDER_API_KEY` in environment variables. diff --git a/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py b/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py new file mode 100644 index 000000000..c924f6136 --- /dev/null +++ b/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py @@ -0,0 +1,44 @@ +from typing import Optional, Any, Type, Dict, Literal +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class SpiderToolSchema(BaseModel): + url: str = Field(description="Website URL") + params: Optional[Dict[str, Any]] = Field(default={"return_format": "markdown"}, description="Specified Params, see https://spider.cloud/docs/api for all availabe params") + mode: Optional[Literal["scrape", "crawl"]] = Field(defualt="scrape", description="Mode, either `scrape` or `crawl` the url") + +class SpiderTool(BaseTool): + name: str = "Spider scrape & crawl tool" + description: str = "Scrape & Crawl any url and return LLM-ready data." + args_schema: Type[BaseModel] = SpiderToolSchema + api_key: Optional[str] = None + spider: Optional[Any] = None + + def __init__(self, api_key: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + try: + from spider import Spider # type: ignore + except ImportError: + raise ImportError( + "`spider-client` package not found, please run `pip install spider-client`" + ) + + self.spider = Spider(api_key=api_key) + + def _run(self, url: str, params: Optional[Dict[str, Any]] = None, mode: Optional[Literal["scrape", "crawl"]] = "scrape"): + if mode != "scrape" and mode != "crawl": + raise ValueError( + "Unknown mode in `mode` parameter, `scrape` or `crawl` is the allowed modes" + ) + + if params is None: + params = {"return_format": "markdown"} + + action = ( + self.spider.scrape_url if mode == "scrape" else self.spider.crawl_url + ) + spider_docs = action(url=url, params=params) + + + print(spider_docs) + return spider_docs From 0b494036352409ed02a6d377307d69194fa19a39 Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Tue, 21 May 2024 12:06:08 +0200 Subject: [PATCH 05/62] remove print from testing --- src/crewai_tools/tools/spider_crawl_tool/spider_tool.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py b/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py index c924f6136..aeb922c74 100644 --- a/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py +++ b/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py @@ -39,6 +39,4 @@ class SpiderTool(BaseTool): ) spider_docs = action(url=url, params=params) - - print(spider_docs) return spider_docs From dd15dab111a743d80c15126f09c1f99f45b7045e Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Tue, 21 May 2024 21:26:12 +0200 Subject: [PATCH 06/62] added full params --- .../tools/spider_crawl_tool/README.md | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/spider_crawl_tool/README.md b/src/crewai_tools/tools/spider_crawl_tool/README.md index 3207efcca..e0734bcf9 100644 --- a/src/crewai_tools/tools/spider_crawl_tool/README.md +++ b/src/crewai_tools/tools/spider_crawl_tool/README.md @@ -24,4 +24,30 @@ tool = SpiderTool() ## Arguments -- `api_key`: Optional. Specifies Spider API key. If not specified it looks for `SPIDER_API_KEY` in environment variables. +- `api_key` (string, optional): Specifies Spider API key. If not specified, it looks for `SPIDER_API_KEY` in environment variables. +- `params` (object, optional): Optional parameters for the request. Defaults to `{"return_format": "markdown"}` to return the website's content in a format that fits LLMs better. + - `request` (string): The request type to perform. Possible values are `http`, `chrome`, and `smart`. Use `smart` to perform an HTTP request by default until JavaScript rendering is needed for the HTML. + - `limit` (int): The maximum number of pages allowed to crawl per website. Remove the value or set it to `0` to crawl all pages. + - `depth` (int): The crawl limit for maximum depth. If `0`, no limit will be applied. + - `cache` (bool): Use HTTP caching for the crawl to speed up repeated runs. Default is `true`. + - `budget` (object): Object that has paths with a counter for limiting the amount of pages example `{"*":1}` for only crawling the root page. + - `locale` (string): The locale to use for request, example `en-US`. + - `cookies` (string): Add HTTP cookies to use for request. + - `stealth` (bool): Use stealth mode for headless chrome request to help prevent being blocked. The default is `true` on chrome. + - `headers` (object): Forward HTTP headers to use for all request. The object is expected to be a map of key value pairs. + - `metadata` (bool): Boolean to store metadata about the pages and content found. This could help improve AI interopt. Defaults to `false` unless you have the website already stored with the configuration enabled. + - `viewport` (object): Configure the viewport for chrome. Defaults to `800x600`. + - `encoding` (string): The type of encoding to use like `UTF-8`, `SHIFT_JIS`, or etc. + - `subdomains` (bool): Allow subdomains to be included. Default is `false`. + - `user_agent` (string): Add a custom HTTP user agent to the request. By default this is set to a random agent. + - `store_data` (bool): Boolean to determine if storage should be used. If set this takes precedence over `storageless`. Defaults to `false`. + - `gpt_config` (object): Use AI to generate actions to perform during the crawl. You can pass an array for the `"prompt"` to chain steps. + - `fingerprint` (bool): Use advanced fingerprint for chrome. + - `storageless` (bool): Boolean to prevent storing any type of data for the request including storage and AI vectors embedding. Defaults to `false` unless you have the website already stored. + - `readability` (bool): Use [readability](https://github.com/mozilla/readability) to pre-process the content for reading. This may drastically improve the content for LLM usage. + `return_format` (string): The format to return the data in. Possible values are `markdown`, `raw`, `text`, and `html2text`. Use `raw` to return the default format of the page like HTML etc. + - `proxy_enabled` (bool): Enable high performance premium proxies for the request to prevent being blocked at the network level. + - `query_selector` (string): The CSS query selector to use when extracting content from the markup. + - `full_resources` (bool): Crawl and download all the resources for a website. + - `request_timeout` (int): The timeout to use for request. Timeouts can be from `5-60`. The default is `30` seconds. + - `run_in_background` (bool): Run the request in the background. Useful if storing data and wanting to trigger crawls to the dashboard. This has no effect if storageless is set. From 60eb6e7c6f7565e8d97099bc0da24c75be149b2b Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Tue, 21 May 2024 23:34:05 +0200 Subject: [PATCH 07/62] spider_tool working, not spider_full_tool --- src/crewai_tools/tools/__init__.py | 2 + .../tools/spider_full_tool/README.md | 55 ++++++++++++++ .../spider_full_tool/spider_full_tool.py | 75 +++++++++++++++++++ .../README.md | 2 +- .../spider_tool.py | 6 +- tests/spider_full_tool_test.py | 38 ++++++++++ tests/spider_tool_test.py | 31 ++++++++ 7 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 src/crewai_tools/tools/spider_full_tool/README.md create mode 100644 src/crewai_tools/tools/spider_full_tool/spider_full_tool.py rename src/crewai_tools/tools/{spider_crawl_tool => spider_tool}/README.md (91%) rename src/crewai_tools/tools/{spider_crawl_tool => spider_tool}/spider_tool.py (86%) create mode 100644 tests/spider_full_tool_test.py create mode 100644 tests/spider_tool_test.py diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 648671d97..7b794508d 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -21,3 +21,5 @@ from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool +from .spider_tool.spider_tool import SpiderTool +from .spider_full_tool.spider_full_tool import SpiderFullTool \ No newline at end of file diff --git a/src/crewai_tools/tools/spider_full_tool/README.md b/src/crewai_tools/tools/spider_full_tool/README.md new file mode 100644 index 000000000..f2e1d536c --- /dev/null +++ b/src/crewai_tools/tools/spider_full_tool/README.md @@ -0,0 +1,55 @@ +# SpiderFullTool + +## Description + +This is the full fledged Spider tool, with all the possible params listed to the agent. This can eat ut tokens and be a big chunk of your token limit, if this is a problem, check out the `SpiderTool` which probably has most of the features you are looking for. But if you truly want to experience the full power of Spider... + +[Spider](https://spider.cloud/?ref=crewai) is the [fastest](https://github.com/spider-rs/spider/blob/main/benches/BENCHMARKS.md#benchmark-results) open source scraper and crawler that returns LLM-ready data. It converts any website into pure HTML, markdown, metadata or text while enabling you to crawl with custom actions using AI. + +## Installation + +To use the Spider API you need to download the [Spider SDK](https://pypi.org/project/spider-client/) and the crewai[tools] SDK too: + +```python +pip install spider-client 'crewai[tools]' +``` + +## Example + +This example shows you how you can use the full Spider tool to enable your agent to scrape and crawl websites. The data returned from the Spider API is already LLM-ready, so no need to do any cleaning there. + +```python +from crewai_tools import SpiderFullTool + +tool = SpiderFullTool() +``` + +## Arguments + +- `api_key` (string, optional): Specifies Spider API key. If not specified, it looks for `SPIDER_API_KEY` in environment variables. +- `params` (object, optional): Optional parameters for the request. Defaults to `{"return_format": "markdown"}` to return the website's content in a format that fits LLMs better. + - `request` (string): The request type to perform. Possible values are `http`, `chrome`, and `smart`. Use `smart` to perform an HTTP request by default until JavaScript rendering is needed for the HTML. + - `limit` (int): The maximum number of pages allowed to crawl per website. Remove the value or set it to `0` to crawl all pages. + - `depth` (int): The crawl limit for maximum depth. If `0`, no limit will be applied. + - `cache` (bool): Use HTTP caching for the crawl to speed up repeated runs. Default is `true`. + - `budget` (object): Object that has paths with a counter for limiting the amount of pages example `{"*":1}` for only crawling the root page. + - `locale` (string): The locale to use for request, example `en-US`. + - `cookies` (string): Add HTTP cookies to use for request. + - `stealth` (bool): Use stealth mode for headless chrome request to help prevent being blocked. The default is `true` on chrome. + - `headers` (object): Forward HTTP headers to use for all request. The object is expected to be a map of key value pairs. + - `metadata` (bool): Boolean to store metadata about the pages and content found. This could help improve AI interopt. Defaults to `false` unless you have the website already stored with the configuration enabled. + - `viewport` (object): Configure the viewport for chrome. Defaults to `800x600`. + - `encoding` (string): The type of encoding to use like `UTF-8`, `SHIFT_JIS`, or etc. + - `subdomains` (bool): Allow subdomains to be included. Default is `false`. + - `user_agent` (string): Add a custom HTTP user agent to the request. By default this is set to a random agent. + - `store_data` (bool): Boolean to determine if storage should be used. If set this takes precedence over `storageless`. Defaults to `false`. + - `gpt_config` (object): Use AI to generate actions to perform during the crawl. You can pass an array for the `"prompt"` to chain steps. + - `fingerprint` (bool): Use advanced fingerprint for chrome. + - `storageless` (bool): Boolean to prevent storing any type of data for the request including storage and AI vectors embedding. Defaults to `false` unless you have the website already stored. + - `readability` (bool): Use [readability](https://github.com/mozilla/readability) to pre-process the content for reading. This may drastically improve the content for LLM usage. + `return_format` (string): The format to return the data in. Possible values are `markdown`, `raw`, `text`, and `html2text`. Use `raw` to return the default format of the page like HTML etc. + - `proxy_enabled` (bool): Enable high performance premium proxies for the request to prevent being blocked at the network level. + - `query_selector` (string): The CSS query selector to use when extracting content from the markup. + - `full_resources` (bool): Crawl and download all the resources for a website. + - `request_timeout` (int): The timeout to use for request. Timeouts can be from `5-60`. The default is `30` seconds. + - `run_in_background` (bool): Run the request in the background. Useful if storing data and wanting to trigger crawls to the dashboard. This has no effect if storageless is set. diff --git a/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py b/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py new file mode 100644 index 000000000..e1041b701 --- /dev/null +++ b/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py @@ -0,0 +1,75 @@ +from typing import Optional, Any, Type, Dict, Literal +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class SpiderFullParams(BaseModel): + request: Optional[str] = Field(description="The request type to perform. Possible values are `http`, `chrome`, and `smart`.") + limit: Optional[int] = Field(description="The maximum number of pages allowed to crawl per website. Remove the value or set it to `0` to crawl all pages.") + depth: Optional[int] = Field(description="The crawl limit for maximum depth. If `0`, no limit will be applied.") + cache: Optional[bool] = Field(default=True, description="Use HTTP caching for the crawl to speed up repeated runs.") + budget: Optional[Dict[str, int]] = Field(description="Object that has paths with a counter for limiting the number of pages, e.g., `{'*':1}` for only crawling the root page.") + locale: Optional[str] = Field(description="The locale to use for request, e.g., `en-US`.") + cookies: Optional[str] = Field(description="Add HTTP cookies to use for request.") + stealth: Optional[bool] = Field(default=True, description="Use stealth mode for headless chrome request to help prevent being blocked. Default is `true` on chrome.") + headers: Optional[Dict[str, str]] = Field(description="Forward HTTP headers to use for all requests. The object is expected to be a map of key-value pairs.") + metadata: Optional[bool] = Field(default=False, description="Boolean to store metadata about the pages and content found. Defaults to `false` unless enabled.") + viewport: Optional[str] = Field(default="800x600", description="Configure the viewport for chrome. Defaults to `800x600`.") + encoding: Optional[str] = Field(description="The type of encoding to use, e.g., `UTF-8`, `SHIFT_JIS`.") + subdomains: Optional[bool] = Field(default=False, description="Allow subdomains to be included. Default is `false`.") + user_agent: Optional[str] = Field(description="Add a custom HTTP user agent to the request. Default is a random agent.") + store_data: Optional[bool] = Field(default=False, description="Boolean to determine if storage should be used. Defaults to `false`.") + gpt_config: Optional[Dict[str, Any]] = Field(description="Use AI to generate actions to perform during the crawl. Can pass an array for the `prompt` to chain steps.") + fingerprint: Optional[bool] = Field(description="Use advanced fingerprinting for chrome.") + storageless: Optional[bool] = Field(default=False, description="Boolean to prevent storing any data for the request. Defaults to `false`.") + readability: Optional[bool] = Field(description="Use readability to pre-process the content for reading.") + return_format: Optional[str] = Field(default="markdown", description="The format to return the data in. Possible values are `markdown`, `raw`, `text`, and `html2text`.") + proxy_enabled: Optional[bool] = Field(description="Enable high-performance premium proxies to prevent being blocked.") + query_selector: Optional[str] = Field(description="The CSS query selector to use when extracting content from the markup.") + full_resources: Optional[bool] = Field(description="Crawl and download all resources for a website.") + request_timeout: Optional[int] = Field(default=30, description="The timeout for requests. Ranges from `5-60` seconds. Default is `30` seconds.") + run_in_background: Optional[bool] = Field(description="Run the request in the background. Useful if storing data and triggering crawls to the dashboard.") + +class SpiderFullToolSchema(BaseModel): + url: str = Field(description="Website URL") + params: Optional[SpiderFullParams] = Field(default=SpiderFullParams(), description="All the params available") + mode: Optional[Literal["scrape", "crawl"]] = Field(default="scrape", description="Mode, either `scrape` or `crawl` the URL") + +class SpiderFullTool(BaseTool): + name: str = "Spider scrape & crawl tool" + description: str = "Scrape & Crawl any URL and return LLM-ready data." + args_schema: Type[BaseModel] = SpiderFullToolSchema + api_key: Optional[str] = None + spider: Optional[Any] = None + + def __init__(self, api_key: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + try: + from spider import Spider # type: ignore + except ImportError: + raise ImportError( + "`spider-client` package not found, please run `pip install spider-client`" + ) + + self.spider = Spider(api_key=api_key) + + def _run( + self, + url: str, + params: Optional[SpiderFullParams] = None, + mode: Optional[Literal["scrape", "crawl"]] = "scrape" + ): + if mode not in ["scrape", "crawl"]: + raise ValueError( + "Unknown mode in `mode` parameter, `scrape` or `crawl` are the allowed modes" + ) + + if params is None: + params = SpiderFullParams() + + action = self.spider.scrape_url if mode == "scrape" else self.spider.crawl_url + spider_docs = action(url=url, params=params.dict()) + + return spider_docs + +tool = SpiderFullTool() +tool._run(url="https://spider.cloud") \ No newline at end of file diff --git a/src/crewai_tools/tools/spider_crawl_tool/README.md b/src/crewai_tools/tools/spider_tool/README.md similarity index 91% rename from src/crewai_tools/tools/spider_crawl_tool/README.md rename to src/crewai_tools/tools/spider_tool/README.md index e0734bcf9..c608b5f5f 100644 --- a/src/crewai_tools/tools/spider_crawl_tool/README.md +++ b/src/crewai_tools/tools/spider_tool/README.md @@ -2,7 +2,7 @@ ## Description -[Spider](https://spider.cloud) is the [fastest]([Spider](https://spider.cloud/?ref=crewai) is the [fastest](https://github.com/spider-rs/spider/blob/main/benches/BENCHMARKS.md#benchmark-results) open source scraper and crawler that returns LLM-ready data. It converts any website into pure HTML, markdown, metadata or text while enabling you to crawl with custom actions using AI. +[Spider](https://spider.cloud/?ref=crewai) is the [fastest](https://github.com/spider-rs/spider/blob/main/benches/BENCHMARKS.md#benchmark-results) open source scraper and crawler that returns LLM-ready data. It converts any website into pure HTML, markdown, metadata or text while enabling you to crawl with custom actions using AI. ## Installation diff --git a/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py b/src/crewai_tools/tools/spider_tool/spider_tool.py similarity index 86% rename from src/crewai_tools/tools/spider_crawl_tool/spider_tool.py rename to src/crewai_tools/tools/spider_tool/spider_tool.py index aeb922c74..73df77ac2 100644 --- a/src/crewai_tools/tools/spider_crawl_tool/spider_tool.py +++ b/src/crewai_tools/tools/spider_tool/spider_tool.py @@ -4,8 +4,8 @@ from crewai_tools.tools.base_tool import BaseTool class SpiderToolSchema(BaseModel): url: str = Field(description="Website URL") - params: Optional[Dict[str, Any]] = Field(default={"return_format": "markdown"}, description="Specified Params, see https://spider.cloud/docs/api for all availabe params") - mode: Optional[Literal["scrape", "crawl"]] = Field(defualt="scrape", description="Mode, either `scrape` or `crawl` the url") + params: Optional[Dict[str, Any]] = Field(default={"return_format": "markdown"}, description="Set additional params. Leave empty for this to return LLM-ready data") + mode: Optional[Literal["scrape", "crawl"]] = Field(defualt="scrape", description="Mode, the only two allowed modes are `scrape` or `crawl` the url") class SpiderTool(BaseTool): name: str = "Spider scrape & crawl tool" @@ -31,7 +31,7 @@ class SpiderTool(BaseTool): "Unknown mode in `mode` parameter, `scrape` or `crawl` is the allowed modes" ) - if params is None: + if params is None or params == {}: params = {"return_format": "markdown"} action = ( diff --git a/tests/spider_full_tool_test.py b/tests/spider_full_tool_test.py new file mode 100644 index 000000000..f00c0ec9c --- /dev/null +++ b/tests/spider_full_tool_test.py @@ -0,0 +1,38 @@ +import os +from crewai_tools.tools.spider_full_tool.spider_full_tool import SpiderFullTool, SpiderFullParams +from crewai import Agent, Task, Crew + +def test_spider_tool(): + spider_tool = SpiderFullTool() + + params = SpiderFullParams( + return_format="markdown" + ) + + docs = spider_tool._run("https://spider.cloud", params=params) + print(docs) + + # searcher = Agent( + # role="Web Research Expert", + # goal="Find related information from specific URL's", + # backstory="An expert web researcher that uses the web extremely well", + # tools=[spider_tool], + # verbose=True + # ) + + # summarize_spider = Task( + # description="Summarize the content of spider.cloud", + # expected_output="A summary that goes over what spider does", + # agent=searcher + # ) + + # crew = Crew( + # agents=[searcher], + # tasks=[summarize_spider], + # verbose=2 + # ) + + # crew.kickoff() + +if __name__ == "__main__": + test_spider_tool() \ No newline at end of file diff --git a/tests/spider_tool_test.py b/tests/spider_tool_test.py new file mode 100644 index 000000000..67e5802a2 --- /dev/null +++ b/tests/spider_tool_test.py @@ -0,0 +1,31 @@ +import os +from crewai_tools.tools.spider_tool.spider_tool import SpiderTool +from crewai import Agent, Task, Crew + +def test_spider_tool(): + spider_tool = SpiderTool() + + searcher = Agent( + role="Web Research Expert", + goal="Find related information from specific URL's", + backstory="An expert web researcher that uses the web extremely well", + tools=[spider_tool], + verbose=True + ) + + summarize_spider = Task( + description="Summarize the content of spider.cloud", + expected_output="A summary that goes over what spider does", + agent=searcher + ) + + crew = Crew( + agents=[searcher], + tasks=[summarize_spider], + verbose=2 + ) + + crew.kickoff() + +if __name__ == "__main__": + test_spider_tool() \ No newline at end of file From 70b5a3ab853db3ab36d97e792f2124a7cfa5b8c9 Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Wed, 22 May 2024 17:05:46 +0200 Subject: [PATCH 08/62] fixed white space --- src/crewai_tools/tools/spider_tool/spider_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/spider_tool/spider_tool.py b/src/crewai_tools/tools/spider_tool/spider_tool.py index 73df77ac2..3495d55c9 100644 --- a/src/crewai_tools/tools/spider_tool/spider_tool.py +++ b/src/crewai_tools/tools/spider_tool/spider_tool.py @@ -33,7 +33,7 @@ class SpiderTool(BaseTool): if params is None or params == {}: params = {"return_format": "markdown"} - + action = ( self.spider.scrape_url if mode == "scrape" else self.spider.crawl_url ) From 5b7276c0bb75c2557ce0e7b6f08d316fb0a6426e Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Thu, 23 May 2024 12:03:48 +0200 Subject: [PATCH 09/62] x --- .../spider_full_tool/spider_full_tool.py | 18 +++++-- .../tools/spider_tool/spider_tool.py | 11 ++-- tests/spider_full_tool_test.py | 54 ++++++++----------- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py b/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py index e1041b701..5d8ea6eda 100644 --- a/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py +++ b/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py @@ -1,6 +1,7 @@ from typing import Optional, Any, Type, Dict, Literal from pydantic.v1 import BaseModel, Field from crewai_tools.tools.base_tool import BaseTool +import requests class SpiderFullParams(BaseModel): request: Optional[str] = Field(description="The request type to perform. Possible values are `http`, `chrome`, and `smart`.") @@ -64,12 +65,21 @@ class SpiderFullTool(BaseTool): ) if params is None: + print("PARAMS IT NONE") params = SpiderFullParams() + print(params) action = self.spider.scrape_url if mode == "scrape" else self.spider.crawl_url - spider_docs = action(url=url, params=params.dict()) + response = action(url=url, params=params.dict()) + + # Debugging: Print the response content + print(f"Response status code: {response.status_code}") + print(f"Response content: {response.text}") + + try: + spider_docs = response.json() + except requests.exceptions.JSONDecodeError as e: + print(f"JSONDecodeError: {e}") + spider_docs = {"error": "Failed to decode JSON response"} return spider_docs - -tool = SpiderFullTool() -tool._run(url="https://spider.cloud") \ No newline at end of file diff --git a/src/crewai_tools/tools/spider_tool/spider_tool.py b/src/crewai_tools/tools/spider_tool/spider_tool.py index 3495d55c9..e020a599a 100644 --- a/src/crewai_tools/tools/spider_tool/spider_tool.py +++ b/src/crewai_tools/tools/spider_tool/spider_tool.py @@ -25,10 +25,15 @@ class SpiderTool(BaseTool): self.spider = Spider(api_key=api_key) - def _run(self, url: str, params: Optional[Dict[str, Any]] = None, mode: Optional[Literal["scrape", "crawl"]] = "scrape"): - if mode != "scrape" and mode != "crawl": + def _run( + self, + url: str, + params: Optional[Dict[str, any]] = None, + mode: Optional[Literal["scrape", "crawl"]] = "scrape" + ): + if mode not in ["scrape", "crawl"]: raise ValueError( - "Unknown mode in `mode` parameter, `scrape` or `crawl` is the allowed modes" + "Unknown mode in `mode` parameter, `scrape` or `crawl` are the allowed modes" ) if params is None or params == {}: diff --git a/tests/spider_full_tool_test.py b/tests/spider_full_tool_test.py index f00c0ec9c..220acfb49 100644 --- a/tests/spider_full_tool_test.py +++ b/tests/spider_full_tool_test.py @@ -1,38 +1,30 @@ -import os from crewai_tools.tools.spider_full_tool.spider_full_tool import SpiderFullTool, SpiderFullParams -from crewai import Agent, Task, Crew - -def test_spider_tool(): - spider_tool = SpiderFullTool() +def test_spider_full_tool(): + spider_tool = SpiderFullTool(api_key="your_api_key") + url = "https://spider.cloud" params = SpiderFullParams( - return_format="markdown" + request="http", + limit=1, + depth=1, + cache=True, + locale="en-US", + stealth=True, + headers={"User-Agent": "test-agent"}, + metadata=False, + viewport="800x600", + encoding="UTF-8", + subdomains=False, + user_agent="test-agent", + store_data=False, + proxy_enabled=False, + query_selector=None, + full_resources=False, + request_timeout=30, + run_in_background=False ) - - docs = spider_tool._run("https://spider.cloud", params=params) + docs = spider_tool._run(url=url, params=params) print(docs) - - # searcher = Agent( - # role="Web Research Expert", - # goal="Find related information from specific URL's", - # backstory="An expert web researcher that uses the web extremely well", - # tools=[spider_tool], - # verbose=True - # ) - - # summarize_spider = Task( - # description="Summarize the content of spider.cloud", - # expected_output="A summary that goes over what spider does", - # agent=searcher - # ) - - # crew = Crew( - # agents=[searcher], - # tasks=[summarize_spider], - # verbose=2 - # ) - - # crew.kickoff() if __name__ == "__main__": - test_spider_tool() \ No newline at end of file + test_spider_full_tool() From 438c979a2e29b0865a8334980414434638e9c082 Mon Sep 17 00:00:00 2001 From: SuperMuel <69467005+SuperMuel@users.noreply.github.com> Date: Thu, 23 May 2024 13:51:17 +0200 Subject: [PATCH 10/62] Add n_results, country, location and locale parameters to payload --- .../tools/serper_dev_tool/serper_dev_tool.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py index 927c0e3b3..9a571cdac 100644 --- a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py +++ b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py @@ -2,7 +2,7 @@ import os import json import requests -from typing import Type, Any +from typing import Optional, Type, Any from pydantic.v1 import BaseModel, Field from crewai_tools.tools.base_tool import BaseTool @@ -16,18 +16,27 @@ class SerperDevTool(BaseTool): args_schema: Type[BaseModel] = SerperDevToolSchema search_url: str = "https://google.serper.dev/search" n_results: int = 10 + country: Optional[str] = None + location: Optional[str] = None + locale: Optional[str] = None def _run( self, **kwargs: Any, ) -> Any: - search_query = kwargs.get('search_query') - if search_query is None: - search_query = kwargs.get('query') + search_query = kwargs.get('search_query') or kwargs.get('query') - payload = json.dumps({"q": search_query}) + payload = json.dumps( + { + "q": search_query, + "num": self.n_results, + "gl": self.country, + "location": self.location, + "hl": self.locale, + } + ) headers = { - 'X-API-KEY': os.environ['SERPER_API_KEY'], + 'X-API-KEY': os.environ['SERPER_API_KEY'], 'content-type': 'application/json' } response = requests.request("POST", self.search_url, headers=headers, data=payload) From 56146b7df43849ae696d8afc2100f505ff650962 Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Sat, 25 May 2024 22:22:50 +0200 Subject: [PATCH 11/62] remove full tool, refined tool --- .../tools/spider_full_tool/README.md | 55 ------------ .../spider_full_tool/spider_full_tool.py | 85 ------------------- .../tools/spider_tool/spider_tool.py | 20 ++++- tests/spider_full_tool_test.py | 30 ------- tests/spider_tool_test.py | 31 +++++-- 5 files changed, 40 insertions(+), 181 deletions(-) delete mode 100644 src/crewai_tools/tools/spider_full_tool/README.md delete mode 100644 src/crewai_tools/tools/spider_full_tool/spider_full_tool.py delete mode 100644 tests/spider_full_tool_test.py diff --git a/src/crewai_tools/tools/spider_full_tool/README.md b/src/crewai_tools/tools/spider_full_tool/README.md deleted file mode 100644 index f2e1d536c..000000000 --- a/src/crewai_tools/tools/spider_full_tool/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# SpiderFullTool - -## Description - -This is the full fledged Spider tool, with all the possible params listed to the agent. This can eat ut tokens and be a big chunk of your token limit, if this is a problem, check out the `SpiderTool` which probably has most of the features you are looking for. But if you truly want to experience the full power of Spider... - -[Spider](https://spider.cloud/?ref=crewai) is the [fastest](https://github.com/spider-rs/spider/blob/main/benches/BENCHMARKS.md#benchmark-results) open source scraper and crawler that returns LLM-ready data. It converts any website into pure HTML, markdown, metadata or text while enabling you to crawl with custom actions using AI. - -## Installation - -To use the Spider API you need to download the [Spider SDK](https://pypi.org/project/spider-client/) and the crewai[tools] SDK too: - -```python -pip install spider-client 'crewai[tools]' -``` - -## Example - -This example shows you how you can use the full Spider tool to enable your agent to scrape and crawl websites. The data returned from the Spider API is already LLM-ready, so no need to do any cleaning there. - -```python -from crewai_tools import SpiderFullTool - -tool = SpiderFullTool() -``` - -## Arguments - -- `api_key` (string, optional): Specifies Spider API key. If not specified, it looks for `SPIDER_API_KEY` in environment variables. -- `params` (object, optional): Optional parameters for the request. Defaults to `{"return_format": "markdown"}` to return the website's content in a format that fits LLMs better. - - `request` (string): The request type to perform. Possible values are `http`, `chrome`, and `smart`. Use `smart` to perform an HTTP request by default until JavaScript rendering is needed for the HTML. - - `limit` (int): The maximum number of pages allowed to crawl per website. Remove the value or set it to `0` to crawl all pages. - - `depth` (int): The crawl limit for maximum depth. If `0`, no limit will be applied. - - `cache` (bool): Use HTTP caching for the crawl to speed up repeated runs. Default is `true`. - - `budget` (object): Object that has paths with a counter for limiting the amount of pages example `{"*":1}` for only crawling the root page. - - `locale` (string): The locale to use for request, example `en-US`. - - `cookies` (string): Add HTTP cookies to use for request. - - `stealth` (bool): Use stealth mode for headless chrome request to help prevent being blocked. The default is `true` on chrome. - - `headers` (object): Forward HTTP headers to use for all request. The object is expected to be a map of key value pairs. - - `metadata` (bool): Boolean to store metadata about the pages and content found. This could help improve AI interopt. Defaults to `false` unless you have the website already stored with the configuration enabled. - - `viewport` (object): Configure the viewport for chrome. Defaults to `800x600`. - - `encoding` (string): The type of encoding to use like `UTF-8`, `SHIFT_JIS`, or etc. - - `subdomains` (bool): Allow subdomains to be included. Default is `false`. - - `user_agent` (string): Add a custom HTTP user agent to the request. By default this is set to a random agent. - - `store_data` (bool): Boolean to determine if storage should be used. If set this takes precedence over `storageless`. Defaults to `false`. - - `gpt_config` (object): Use AI to generate actions to perform during the crawl. You can pass an array for the `"prompt"` to chain steps. - - `fingerprint` (bool): Use advanced fingerprint for chrome. - - `storageless` (bool): Boolean to prevent storing any type of data for the request including storage and AI vectors embedding. Defaults to `false` unless you have the website already stored. - - `readability` (bool): Use [readability](https://github.com/mozilla/readability) to pre-process the content for reading. This may drastically improve the content for LLM usage. - `return_format` (string): The format to return the data in. Possible values are `markdown`, `raw`, `text`, and `html2text`. Use `raw` to return the default format of the page like HTML etc. - - `proxy_enabled` (bool): Enable high performance premium proxies for the request to prevent being blocked at the network level. - - `query_selector` (string): The CSS query selector to use when extracting content from the markup. - - `full_resources` (bool): Crawl and download all the resources for a website. - - `request_timeout` (int): The timeout to use for request. Timeouts can be from `5-60`. The default is `30` seconds. - - `run_in_background` (bool): Run the request in the background. Useful if storing data and wanting to trigger crawls to the dashboard. This has no effect if storageless is set. diff --git a/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py b/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py deleted file mode 100644 index 5d8ea6eda..000000000 --- a/src/crewai_tools/tools/spider_full_tool/spider_full_tool.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Optional, Any, Type, Dict, Literal -from pydantic.v1 import BaseModel, Field -from crewai_tools.tools.base_tool import BaseTool -import requests - -class SpiderFullParams(BaseModel): - request: Optional[str] = Field(description="The request type to perform. Possible values are `http`, `chrome`, and `smart`.") - limit: Optional[int] = Field(description="The maximum number of pages allowed to crawl per website. Remove the value or set it to `0` to crawl all pages.") - depth: Optional[int] = Field(description="The crawl limit for maximum depth. If `0`, no limit will be applied.") - cache: Optional[bool] = Field(default=True, description="Use HTTP caching for the crawl to speed up repeated runs.") - budget: Optional[Dict[str, int]] = Field(description="Object that has paths with a counter for limiting the number of pages, e.g., `{'*':1}` for only crawling the root page.") - locale: Optional[str] = Field(description="The locale to use for request, e.g., `en-US`.") - cookies: Optional[str] = Field(description="Add HTTP cookies to use for request.") - stealth: Optional[bool] = Field(default=True, description="Use stealth mode for headless chrome request to help prevent being blocked. Default is `true` on chrome.") - headers: Optional[Dict[str, str]] = Field(description="Forward HTTP headers to use for all requests. The object is expected to be a map of key-value pairs.") - metadata: Optional[bool] = Field(default=False, description="Boolean to store metadata about the pages and content found. Defaults to `false` unless enabled.") - viewport: Optional[str] = Field(default="800x600", description="Configure the viewport for chrome. Defaults to `800x600`.") - encoding: Optional[str] = Field(description="The type of encoding to use, e.g., `UTF-8`, `SHIFT_JIS`.") - subdomains: Optional[bool] = Field(default=False, description="Allow subdomains to be included. Default is `false`.") - user_agent: Optional[str] = Field(description="Add a custom HTTP user agent to the request. Default is a random agent.") - store_data: Optional[bool] = Field(default=False, description="Boolean to determine if storage should be used. Defaults to `false`.") - gpt_config: Optional[Dict[str, Any]] = Field(description="Use AI to generate actions to perform during the crawl. Can pass an array for the `prompt` to chain steps.") - fingerprint: Optional[bool] = Field(description="Use advanced fingerprinting for chrome.") - storageless: Optional[bool] = Field(default=False, description="Boolean to prevent storing any data for the request. Defaults to `false`.") - readability: Optional[bool] = Field(description="Use readability to pre-process the content for reading.") - return_format: Optional[str] = Field(default="markdown", description="The format to return the data in. Possible values are `markdown`, `raw`, `text`, and `html2text`.") - proxy_enabled: Optional[bool] = Field(description="Enable high-performance premium proxies to prevent being blocked.") - query_selector: Optional[str] = Field(description="The CSS query selector to use when extracting content from the markup.") - full_resources: Optional[bool] = Field(description="Crawl and download all resources for a website.") - request_timeout: Optional[int] = Field(default=30, description="The timeout for requests. Ranges from `5-60` seconds. Default is `30` seconds.") - run_in_background: Optional[bool] = Field(description="Run the request in the background. Useful if storing data and triggering crawls to the dashboard.") - -class SpiderFullToolSchema(BaseModel): - url: str = Field(description="Website URL") - params: Optional[SpiderFullParams] = Field(default=SpiderFullParams(), description="All the params available") - mode: Optional[Literal["scrape", "crawl"]] = Field(default="scrape", description="Mode, either `scrape` or `crawl` the URL") - -class SpiderFullTool(BaseTool): - name: str = "Spider scrape & crawl tool" - description: str = "Scrape & Crawl any URL and return LLM-ready data." - args_schema: Type[BaseModel] = SpiderFullToolSchema - api_key: Optional[str] = None - spider: Optional[Any] = None - - def __init__(self, api_key: Optional[str] = None, **kwargs): - super().__init__(**kwargs) - try: - from spider import Spider # type: ignore - except ImportError: - raise ImportError( - "`spider-client` package not found, please run `pip install spider-client`" - ) - - self.spider = Spider(api_key=api_key) - - def _run( - self, - url: str, - params: Optional[SpiderFullParams] = None, - mode: Optional[Literal["scrape", "crawl"]] = "scrape" - ): - if mode not in ["scrape", "crawl"]: - raise ValueError( - "Unknown mode in `mode` parameter, `scrape` or `crawl` are the allowed modes" - ) - - if params is None: - print("PARAMS IT NONE") - params = SpiderFullParams() - print(params) - - action = self.spider.scrape_url if mode == "scrape" else self.spider.crawl_url - response = action(url=url, params=params.dict()) - - # Debugging: Print the response content - print(f"Response status code: {response.status_code}") - print(f"Response content: {response.text}") - - try: - spider_docs = response.json() - except requests.exceptions.JSONDecodeError as e: - print(f"JSONDecodeError: {e}") - spider_docs = {"error": "Failed to decode JSON response"} - - return spider_docs diff --git a/src/crewai_tools/tools/spider_tool/spider_tool.py b/src/crewai_tools/tools/spider_tool/spider_tool.py index e020a599a..9c7f6ad08 100644 --- a/src/crewai_tools/tools/spider_tool/spider_tool.py +++ b/src/crewai_tools/tools/spider_tool/spider_tool.py @@ -4,8 +4,17 @@ from crewai_tools.tools.base_tool import BaseTool class SpiderToolSchema(BaseModel): url: str = Field(description="Website URL") - params: Optional[Dict[str, Any]] = Field(default={"return_format": "markdown"}, description="Set additional params. Leave empty for this to return LLM-ready data") - mode: Optional[Literal["scrape", "crawl"]] = Field(defualt="scrape", description="Mode, the only two allowed modes are `scrape` or `crawl` the url") + params: Optional[Dict[str, Any]] = Field( + description="Set additional params. Options include:\n" + "- `limit`: Optional[int] - The maximum number of pages allowed to crawl per website. Remove the value or set it to `0` to crawl all pages.\n" + "- `depth`: Optional[int] - The crawl limit for maximum depth. If `0`, no limit will be applied.\n" + "- `metadata`: Optional[bool] - Boolean to include metadata or not. Defaults to `False` unless set to `True`. If the user wants metadata, include params.metadata = True.\n" + "- `query_selector`: Optional[str] - The CSS query selector to use when extracting content from the markup.\n" + ) + mode: Literal["scrape", "crawl"] = Field( + default="scrape", + description="Mode, the only two allowed modes are `scrape` or `crawl`. `scrape` will only scrape the one page of the url provided, while `crawl` will crawl the website following all the subpages found." + ) class SpiderTool(BaseTool): name: str = "Spider scrape & crawl tool" @@ -28,7 +37,7 @@ class SpiderTool(BaseTool): def _run( self, url: str, - params: Optional[Dict[str, any]] = None, + params: Optional[Dict[str, Any]] = None, mode: Optional[Literal["scrape", "crawl"]] = "scrape" ): if mode not in ["scrape", "crawl"]: @@ -36,7 +45,10 @@ class SpiderTool(BaseTool): "Unknown mode in `mode` parameter, `scrape` or `crawl` are the allowed modes" ) - if params is None or params == {}: + # Ensure 'return_format': 'markdown' is always included + if params: + params["return_format"] = "markdown" + else: params = {"return_format": "markdown"} action = ( diff --git a/tests/spider_full_tool_test.py b/tests/spider_full_tool_test.py deleted file mode 100644 index 220acfb49..000000000 --- a/tests/spider_full_tool_test.py +++ /dev/null @@ -1,30 +0,0 @@ -from crewai_tools.tools.spider_full_tool.spider_full_tool import SpiderFullTool, SpiderFullParams - -def test_spider_full_tool(): - spider_tool = SpiderFullTool(api_key="your_api_key") - url = "https://spider.cloud" - params = SpiderFullParams( - request="http", - limit=1, - depth=1, - cache=True, - locale="en-US", - stealth=True, - headers={"User-Agent": "test-agent"}, - metadata=False, - viewport="800x600", - encoding="UTF-8", - subdomains=False, - user_agent="test-agent", - store_data=False, - proxy_enabled=False, - query_selector=None, - full_resources=False, - request_timeout=30, - run_in_background=False - ) - docs = spider_tool._run(url=url, params=params) - print(docs) - -if __name__ == "__main__": - test_spider_full_tool() diff --git a/tests/spider_tool_test.py b/tests/spider_tool_test.py index 67e5802a2..7faaa5338 100644 --- a/tests/spider_tool_test.py +++ b/tests/spider_tool_test.py @@ -10,22 +10,39 @@ def test_spider_tool(): goal="Find related information from specific URL's", backstory="An expert web researcher that uses the web extremely well", tools=[spider_tool], - verbose=True + verbose=True, + cache=False ) - summarize_spider = Task( - description="Summarize the content of spider.cloud", - expected_output="A summary that goes over what spider does", + choose_between_scrape_crawl = Task( + description="Scrape the page of spider.cloud and return a summary of how fast it is", + expected_output="spider.cloud is a fast scraping and crawling tool", agent=searcher ) - + + return_metadata = Task( + description="Scrape https://spider.cloud with a limit of 1 and enable metadata", + expected_output="Metadata and 10 word summary of spider.cloud", + agent=searcher + ) + + css_selector = Task( + description="Scrape one page of spider.cloud with the `body > div > main > section.grid.md\:grid-cols-2.gap-10.place-items-center.md\:max-w-screen-xl.mx-auto.pb-8.pt-20 > div:nth-child(1) > h1` CSS selector", + expected_output="The content of the element with the css selector body > div > main > section.grid.md\:grid-cols-2.gap-10.place-items-center.md\:max-w-screen-xl.mx-auto.pb-8.pt-20 > div:nth-child(1) > h1", + agent=searcher + ) + crew = Crew( agents=[searcher], - tasks=[summarize_spider], + tasks=[ + choose_between_scrape_crawl, + return_metadata, + css_selector + ], verbose=2 ) crew.kickoff() if __name__ == "__main__": - test_spider_tool() \ No newline at end of file + test_spider_tool() From 7d40c98434a0480c0085adb1aaed105932a4c992 Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Sat, 25 May 2024 22:28:48 +0200 Subject: [PATCH 12/62] remove full tool import --- src/crewai_tools/tools/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 7b794508d..ea0b16304 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -22,4 +22,3 @@ from .xml_search_tool.xml_search_tool import XMLSearchTool from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool from .spider_tool.spider_tool import SpiderTool -from .spider_full_tool.spider_full_tool import SpiderFullTool \ No newline at end of file From f0f1ab175a96ccc5388d960d71dc29d2bab9487e Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Sat, 25 May 2024 22:36:30 +0200 Subject: [PATCH 13/62] remove unecessary os import --- tests/spider_tool_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/spider_tool_test.py b/tests/spider_tool_test.py index 7faaa5338..977dd8769 100644 --- a/tests/spider_tool_test.py +++ b/tests/spider_tool_test.py @@ -1,4 +1,3 @@ -import os from crewai_tools.tools.spider_tool.spider_tool import SpiderTool from crewai import Agent, Task, Crew From ad965357ce403e165725f9131820f7ba924babf1 Mon Sep 17 00:00:00 2001 From: WilliamEspegren Date: Sat, 25 May 2024 22:40:48 +0200 Subject: [PATCH 14/62] refined spider_tool.py --- src/crewai_tools/tools/spider_tool/README.md | 30 ++++++++++++++++++- .../tools/spider_tool/spider_tool.py | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/crewai_tools/tools/spider_tool/README.md b/src/crewai_tools/tools/spider_tool/README.md index c608b5f5f..563c07a04 100644 --- a/src/crewai_tools/tools/spider_tool/README.md +++ b/src/crewai_tools/tools/spider_tool/README.md @@ -19,7 +19,35 @@ This example shows you how you can use the Spider tool to enable your agent to s ```python from crewai_tools import SpiderTool -tool = SpiderTool() +def main(): + spider_tool = SpiderTool() + + searcher = Agent( + role="Web Research Expert", + goal="Find related information from specific URL's", + backstory="An expert web researcher that uses the web extremely well", + tools=[spider_tool], + verbose=True, + ) + + return_metadata = Task( + description="Scrape https://spider.cloud with a limit of 1 and enable metadata", + expected_output="Metadata and 10 word summary of spider.cloud", + agent=searcher + ) + + crew = Crew( + agents=[searcher], + tasks=[ + return_metadata, + ], + verbose=2 + ) + + crew.kickoff() + +if __name__ == "__main__": + main() ``` ## Arguments diff --git a/src/crewai_tools/tools/spider_tool/spider_tool.py b/src/crewai_tools/tools/spider_tool/spider_tool.py index 9c7f6ad08..b4b230c8e 100644 --- a/src/crewai_tools/tools/spider_tool/spider_tool.py +++ b/src/crewai_tools/tools/spider_tool/spider_tool.py @@ -13,7 +13,7 @@ class SpiderToolSchema(BaseModel): ) mode: Literal["scrape", "crawl"] = Field( default="scrape", - description="Mode, the only two allowed modes are `scrape` or `crawl`. `scrape` will only scrape the one page of the url provided, while `crawl` will crawl the website following all the subpages found." + description="Mode, the only two allowed modes are `scrape` or `crawl`. Use `scrape` to scrape a single page and `crawl` to crawl the entire website following subpages. These modes are the only allowed values even when ANY params is set." ) class SpiderTool(BaseTool): From 53e9b407250ce2b769b4f3912f3794ea3623e0eb Mon Sep 17 00:00:00 2001 From: Mazen Ramadan Date: Mon, 27 May 2024 14:48:38 +0300 Subject: [PATCH 15/62] Add Scrapfly website scrape tool --- src/crewai_tools/__init__.py | 1 + src/crewai_tools/tools/__init__.py | 1 + .../scrapfly_scrape_website_tool/README.md | 57 +++++++++++++++++++ .../scrapfly_scrape_website_tool.py | 47 +++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/crewai_tools/tools/scrapfly_scrape_website_tool/README.md create mode 100644 src/crewai_tools/tools/scrapfly_scrape_website_tool/scrapfly_scrape_website_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index faac5d37d..cc1a4cef4 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -18,6 +18,7 @@ from .tools import ( RagTool, ScrapeElementFromWebsiteTool, ScrapeWebsiteTool, + ScrapflyScrapeWebsiteTool, SeleniumScrapingTool, WebsiteSearchTool, XMLSearchTool, diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 648671d97..1b332a43d 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -16,6 +16,7 @@ from .pg_seach_tool.pg_search_tool import PGSearchTool from .rag.rag_tool import RagTool from .scrape_element_from_website.scrape_element_from_website import ScrapeElementFromWebsiteTool from .scrape_website_tool.scrape_website_tool import ScrapeWebsiteTool +from .scrapfly_scrape_website_tool.scrapfly_scrape_website_tool import ScrapflyScrapeWebsiteTool from .selenium_scraping_tool.selenium_scraping_tool import SeleniumScrapingTool from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool diff --git a/src/crewai_tools/tools/scrapfly_scrape_website_tool/README.md b/src/crewai_tools/tools/scrapfly_scrape_website_tool/README.md new file mode 100644 index 000000000..6ab9c9d52 --- /dev/null +++ b/src/crewai_tools/tools/scrapfly_scrape_website_tool/README.md @@ -0,0 +1,57 @@ +# ScrapflyScrapeWebsiteTool + +## Description +[ScrapFly](https://scrapfly.io/) is a web scraping API with headless browser capabilities, proxies, and anti-bot bypass. It allows for extracting web page data into accessible LLM markdown or text. + +## Setup and Installation +1. **Install ScrapFly Python SDK**: Install `scrapfly-sdk` Python package is installed to use the ScrapFly Web Loader. Install it via pip with the following command: + + ```bash + pip install scrapfly-sdk + ``` + +2. **API Key**: Register for free from [scrapfly.io/register](https://www.scrapfly.io/register/) to obtain your API key. + +## Example Usage + +Utilize the ScrapflyScrapeWebsiteTool as follows to retrieve a web page data as text, markdown (LLM accissible) or HTML: + +```python +from crewai_tools import ScrapflyScrapeWebsiteTool + +tool = ScrapflyScrapeWebsiteTool( + api_key="Your ScrapFly API key" +) + +result = tool._run( + url="https://web-scraping.dev/products", + scrape_format="markdown", + ignore_scrape_failures=True +) +``` + +## Additional Arguments +The ScrapflyScrapeWebsiteTool also allows passigng ScrapeConfig object for customizing the scrape request. See the [API params documentation](https://scrapfly.io/docs/scrape-api/getting-started) for the full feature details and their API params: +```python +from crewai_tools import ScrapflyScrapeWebsiteTool + +tool = ScrapflyScrapeWebsiteTool( + api_key="Your ScrapFly API key" +) + +scrapfly_scrape_config = { + "asp": True, # Bypass scraping blocking and solutions, like Cloudflare + "render_js": True, # Enable JavaScript rendering with a cloud headless browser + "proxy_pool": "public_residential_pool", # Select a proxy pool (datacenter or residnetial) + "country": "us", # Select a proxy location + "auto_scroll": True, # Auto scroll the page + "js": "" # Execute custom JavaScript code by the headless browser +} + +result = tool._run( + url="https://web-scraping.dev/products", + scrape_format="markdown", + ignore_scrape_failures=True, + scrape_config=scrapfly_scrape_config +) +``` \ No newline at end of file diff --git a/src/crewai_tools/tools/scrapfly_scrape_website_tool/scrapfly_scrape_website_tool.py b/src/crewai_tools/tools/scrapfly_scrape_website_tool/scrapfly_scrape_website_tool.py new file mode 100644 index 000000000..b0bfa7ee6 --- /dev/null +++ b/src/crewai_tools/tools/scrapfly_scrape_website_tool/scrapfly_scrape_website_tool.py @@ -0,0 +1,47 @@ +import logging + +from typing import Optional, Any, Type, Dict, Literal +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +logger = logging.getLogger(__file__) + +class ScrapflyScrapeWebsiteToolSchema(BaseModel): + url: str = Field(description="Webpage URL") + scrape_format: Optional[Literal["raw", "markdown", "text"]] = Field(default="markdown", description="Webpage extraction format") + scrape_config: Optional[Dict[str, Any]] = Field(default=None, description="Scrapfly request scrape config") + ignore_scrape_failures: Optional[bool] = Field(default=None, description="whether to ignore failures") + +class ScrapflyScrapeWebsiteTool(BaseTool): + name: str = "Scrapfly web scraping API tool" + description: str = "Scrape a webpage url using Scrapfly and return its content as markdown or text" + args_schema: Type[BaseModel] = ScrapflyScrapeWebsiteToolSchema + api_key: str = None + scrapfly: Optional[Any] = None + + def __init__(self, api_key: str): + super().__init__() + try: + from scrapfly import ScrapflyClient + except ImportError: + raise ImportError( + "`scrapfly` package not found, please run `pip install scrapfly-sdk`" + ) + self.scrapfly = ScrapflyClient(key=api_key) + + def _run(self, url: str, scrape_format: str = "markdown", scrape_config: Optional[Dict[str, Any]] = None, ignore_scrape_failures: Optional[bool] = None): + from scrapfly import ScrapeApiResponse, ScrapeConfig + + scrape_config = scrape_config if scrape_config is not None else {} + try: + response: ScrapeApiResponse = self.scrapfly.scrape( + ScrapeConfig(url, format=scrape_format, **scrape_config) + ) + return response.scrape_result["content"] + except Exception as e: + if ignore_scrape_failures: + logger.error(f"Error fetching data from {url}, exception: {e}") + return None + else: + raise e + \ No newline at end of file From 7ee7d846e2abe079d637a10629c709bf86edd8ac Mon Sep 17 00:00:00 2001 From: Jerry Liu Date: Sat, 8 Jun 2024 21:42:28 -0700 Subject: [PATCH 16/62] cr --- src/crewai_tools/__init__.py | 1 + src/crewai_tools/tools/__init__.py | 1 + .../tools/llamaindex_tool/README.md | 53 ++++++++++++ .../tools/llamaindex_tool/llamaindex_tool.py | 84 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 src/crewai_tools/tools/llamaindex_tool/README.md create mode 100644 src/crewai_tools/tools/llamaindex_tool/llamaindex_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index faac5d37d..a51d70449 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -23,4 +23,5 @@ from .tools import ( XMLSearchTool, YoutubeChannelSearchTool, YoutubeVideoSearchTool, + LlamaIndexTool ) \ No newline at end of file diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 648671d97..4da0c0337 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -21,3 +21,4 @@ from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool +from .llamaindex_tool.llamaindex_tool import LlamaIndexTool diff --git a/src/crewai_tools/tools/llamaindex_tool/README.md b/src/crewai_tools/tools/llamaindex_tool/README.md new file mode 100644 index 000000000..cd8f4cd99 --- /dev/null +++ b/src/crewai_tools/tools/llamaindex_tool/README.md @@ -0,0 +1,53 @@ +# LlamaIndexTool Documentation + +## Description +This tool is designed to be a general wrapper around LlamaIndex tools and query engines, enabling you to leverage LlamaIndex resources +in terms of RAG/agentic pipelines as tools to plug into CrewAI agents. + +## Installation +To incorporate this tool into your project, follow the installation instructions below: +```shell +pip install 'crewai[tools]' +``` + +## Example +The following example demonstrates how to initialize the tool and execute a search with a given query: + +```python +from crewai_tools import LlamaIndexTool + +# Initialize the tool from a LlamaIndex Tool + +## Example 1: Initialize from FunctionTool +from llama_index.core.tools import FunctionTool + +your_python_function = lambda ...: ... +og_tool = FunctionTool.from_defaults(your_python_function, name="", description='') +tool = LlamaIndexTool.from_tool(og_tool) + +## Example 2: Initialize from LlamaHub Tools +from llama_index.tools.wolfram_alpha import WolframAlphaToolSpec +wolfram_spec = WolframAlphaToolSpec(app_id="") +wolfram_tools = wolfram_spec.to_tool_list() +tools = [LlamaIndexTool.from_tool(t) for t in wolfram_tools] + + +# Initialize Tool from a LlamaIndex Query Engine + +## NOTE: LlamaIndex has a lot of query engines, define whatever query engine you want +query_engine = index.as_query_engine() +query_tool = LlamaIndexTool.from_query_engine( + query_engine, + name="Uber 2019 10K Query Tool", + description="Use this tool to lookup the 2019 Uber 10K Annual Report" +) + +``` + +## Steps to Get Started +To effectively use the `LlamaIndexTool`, follow these steps: + +1. **Install CrewAI**: Confirm that the `crewai[tools]` package is installed in your Python environment. +2. **Install and use LlamaIndex**: Follow LlamaIndex documentation (https://docs.llamaindex.ai/) to setup a RAG/agent pipeline. + + diff --git a/src/crewai_tools/tools/llamaindex_tool/llamaindex_tool.py b/src/crewai_tools/tools/llamaindex_tool/llamaindex_tool.py new file mode 100644 index 000000000..5aac51052 --- /dev/null +++ b/src/crewai_tools/tools/llamaindex_tool/llamaindex_tool.py @@ -0,0 +1,84 @@ +import os +import json +import requests + +from typing import Type, Any, cast, Optional +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class LlamaIndexTool(BaseTool): + """Tool to wrap LlamaIndex tools/query engines.""" + llama_index_tool: Any + + def _run( + self, + *args: Any, + **kwargs: Any, + ) -> Any: + """Run tool.""" + from llama_index.core.tools import BaseTool as LlamaBaseTool + tool = cast(LlamaBaseTool, self.llama_index_tool) + return tool(*args, **kwargs) + + @classmethod + def from_tool( + cls, + tool: Any, + **kwargs: Any + ) -> "LlamaIndexTool": + from llama_index.core.tools import BaseTool as LlamaBaseTool + + if not isinstance(tool, LlamaBaseTool): + raise ValueError(f"Expected a LlamaBaseTool, got {type(tool)}") + tool = cast(LlamaBaseTool, tool) + + if tool.metadata.fn_schema is None: + raise ValueError("The LlamaIndex tool does not have an fn_schema specified.") + args_schema = cast(Type[BaseModel], tool.metadata.fn_schema) + + return cls( + name=tool.metadata.name, + description=tool.metadata.description, + args_schema=args_schema, + llama_index_tool=tool, + **kwargs + ) + + + @classmethod + def from_query_engine( + cls, + query_engine: Any, + name: Optional[str] = None, + description: Optional[str] = None, + return_direct: bool = False, + **kwargs: Any + ) -> "LlamaIndexTool": + from llama_index.core.query_engine import BaseQueryEngine + from llama_index.core.tools import QueryEngineTool + + if not isinstance(query_engine, BaseQueryEngine): + raise ValueError(f"Expected a BaseQueryEngine, got {type(query_engine)}") + + # NOTE: by default the schema expects an `input` variable. However this + # confuses crewAI so we are renaming to `query`. + class QueryToolSchema(BaseModel): + """Schema for query tool.""" + query: str = Field(..., description="Search query for the query tool.") + + # NOTE: setting `resolve_input_errors` to True is important because the schema expects `input` but we are using `query` + query_engine_tool = QueryEngineTool.from_defaults( + query_engine, + name=name, + description=description, + return_direct=return_direct, + resolve_input_errors=True, + ) + # HACK: we are replacing the schema with our custom schema + query_engine_tool.metadata.fn_schema = QueryToolSchema + + return cls.from_tool( + query_engine_tool, + **kwargs + ) + \ No newline at end of file From ff80e6cb79d5606753a9a232105c24f64e57c223 Mon Sep 17 00:00:00 2001 From: smsajjadzaidi Date: Mon, 10 Jun 2024 02:54:21 +0500 Subject: [PATCH 17/62] fixed use of arg n_results --- src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py index 927c0e3b3..9c26f6128 100644 --- a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py +++ b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py @@ -33,7 +33,7 @@ class SerperDevTool(BaseTool): response = requests.request("POST", self.search_url, headers=headers, data=payload) results = response.json() if 'organic' in results: - results = results['organic'] + results = results['organic'][:self.n_results] string = [] for result in results: try: @@ -44,7 +44,7 @@ class SerperDevTool(BaseTool): "---" ])) except KeyError: - next + continue content = '\n'.join(string) return f"\nSearch results: {content}\n" From d8b8edab087fa7da4e085c2d83154f3c4a272d63 Mon Sep 17 00:00:00 2001 From: teampen <136991215+teampen@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:15:21 -0400 Subject: [PATCH 18/62] adding google search, sholar, and news --- src/crewai_tools/__init__.py | 3 + src/crewai_tools/tools/__init__.py | 3 + .../tools/serply_api_tool/README.md | 67 +++++++++++++ .../serply_news_search_tool.py | 80 ++++++++++++++++ .../serply_scholar_search_tool.py | 85 +++++++++++++++++ .../serply_api_tool/serply_web_search_tool.py | 93 +++++++++++++++++++ 6 files changed, 331 insertions(+) create mode 100644 src/crewai_tools/tools/serply_api_tool/README.md create mode 100644 src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py create mode 100644 src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py create mode 100644 src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index faac5d37d..a9013b7ee 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -23,4 +23,7 @@ from .tools import ( XMLSearchTool, YoutubeChannelSearchTool, YoutubeVideoSearchTool, + SerplyWebSearchTool, + SerplyNewsSearchTool, + SerplyScholarSearchTool ) \ No newline at end of file diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 648671d97..138dbce17 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -21,3 +21,6 @@ from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool +from .serply_api_tool.serply_web_search_tool import SerplyWebSearchTool +from .serply_api_tool.serply_news_search_tool import SerplyNewsSearchTool +from .serply_api_tool.serply_scholar_search_tool import SerplyScholarSearchTool diff --git a/src/crewai_tools/tools/serply_api_tool/README.md b/src/crewai_tools/tools/serply_api_tool/README.md new file mode 100644 index 000000000..fe439b28f --- /dev/null +++ b/src/crewai_tools/tools/serply_api_tool/README.md @@ -0,0 +1,67 @@ +# Serply API Documentation + +## Description +This tool is designed to perform a web/news/scholar search for a specified query from a text's content across the internet. It utilizes the [Serply.io](https://serply.io) API to fetch and display the most relevant search results based on the query provided by the user. + +## Installation + +To incorporate this tool into your project, follow the installation instructions below: +```shell +pip install 'crewai[tools]' +``` + +## Examples + +## Web Search +The following example demonstrates how to initialize the tool and execute a search the web with a given query: + +```python +from crewai_tools import SerplyWebSearchTool + +# Initialize the tool for internet searching capabilities +tool = SerplyWebSearchTool() + +# increase search limits to 100 results +tool = SerplyWebSearchTool(limit=100) + + +# change results language (fr - French) +tool = SerplyWebSearchTool(hl="fr") +``` + +## News Search +The following example demonstrates how to initialize the tool and execute a search news with a given query: + +```python +from crewai_tools import SerplyNewsSearchTool + +# Initialize the tool for internet searching capabilities +tool = SerplyNewsSearchTool() + +# change country news (JP - Japan) +tool = SerplyNewsSearchTool(proxy_location="JP") +``` + +## Scholar Search +The following example demonstrates how to initialize the tool and execute a search scholar articles a given query: + +```python +from crewai_tools import SerplyScholarSearchTool + +# Initialize the tool for internet searching capabilities +tool = SerplyScholarSearchTool() + +# change country news (GB - Great Britain) +tool = SerplyScholarSearchTool(proxy_location="GB") +``` + + +## Steps to Get Started +To effectively use the `SerplyApiTool`, follow these steps: + +1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment. +2. **API Key Acquisition**: Acquire a `serper.dev` API key by registering for a free account at [Serply.io](https://serply.io). +3. **Environment Configuration**: Store your obtained API key in an environment variable named `SERPLY_API_KEY` to facilitate its use by the tool. + +## Conclusion +By integrating the `SerplyApiTool` into Python projects, users gain the ability to conduct real-time searches, relevant news across the internet directly from their applications. By adhering to the setup and usage guidelines provided, incorporating this tool into projects is streamlined and straightforward. diff --git a/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py new file mode 100644 index 000000000..c1fef5a77 --- /dev/null +++ b/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py @@ -0,0 +1,80 @@ +import os +import requests +from urllib.parse import urlencode +from typing import Type, Any, Optional +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class SerplyNewsSearchToolSchema(BaseModel): + """Input for Serply News Search.""" + search_query: str = Field(..., description="Mandatory search query you want to use to fetch news articles") + + +class SerplyNewsSearchTool(BaseTool): + name: str = "News Search" + description: str = "A tool to perform News article search with a search_query." + args_schema: Type[BaseModel] = SerplyNewsSearchToolSchema + search_url: str = "https://api.serply.io/v1/news/" + proxy_location: Optional[str] = "US" + headers: Optional[dict] = {} + limit: Optional[int] = 10 + + def __init__( + self, + limit: Optional[int] = 10, + proxy_location: Optional[str] = "US", + **kwargs + ): + """ + param: limit (int): The maximum number of results to return [10-100, defaults to 10] + proxy_location: (str): Where to get news, specifically for a specific country results. + ['US', 'CA', 'IE', 'GB', 'FR', 'DE', 'SE', 'IN', 'JP', 'KR', 'SG', 'AU', 'BR'] (defaults to US) + """ + super().__init__(**kwargs) + self.limit = limit + self.proxy_location = proxy_location + self.headers = { + "X-API-KEY": os.environ["SERPLY_API_KEY"], + "User-Agent": "crew-tools", + "X-Proxy-Location": proxy_location + } + + def _run( + self, + **kwargs: Any, + ) -> Any: + # build query parameters + query_payload = {} + + if "query" in kwargs: + query_payload["q"] = kwargs["query"] + elif "search_query" in kwargs: + query_payload["q"] = kwargs["search_query"] + + # build the url + url = f"{self.search_url}{urlencode(query_payload)}" + + response = requests.request("GET", url, headers=self.headers) + results = response.json() + if "entries" in results: + results = results['entries'] + string = [] + for result in results[:self.limit]: + try: + # follow url + r = requests.get(result['link']) + final_link = r.history[-1].headers['Location'] + string.append('\n'.join([ + f"Title: {result['title']}", + f"Link: {final_link}", + f"Source: {result['source']['title']}", + f"Published: {result['published']}", + "---" + ])) + except KeyError: + next + + content = '\n'.join(string) + return f"\nSearch results: {content}\n" + else: + return results diff --git a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py new file mode 100644 index 000000000..badc9950e --- /dev/null +++ b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py @@ -0,0 +1,85 @@ +import os +import requests +from urllib.parse import urlencode +from typing import Type, Any, Optional +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + +class SerplyScholarSearchToolSchema(BaseModel): + """Input for Serply Scholar Search.""" + search_query: str = Field(..., description="Mandatory search query you want to use to fetch scholarly literature") + + +class SerplyScholarSearchTool(BaseTool): + name: str = "Scholar Search" + description: str = "A tool to perform News article search with a search_query." + args_schema: Type[BaseModel] = SerplyScholarSearchToolSchema + search_url: str = "https://api.serply.io/v1/scholar/" + hl: Optional[str] = "us" + proxy_location: Optional[str] = "US" + headers: Optional[dict] = {} + + def __init__( + self, + hl: str = "us", + proxy_location: Optional[str] = "US", + **kwargs + ): + """ + param: hl (str): host Language code to display results in + (reference https://developers.google.com/custom-search/docs/xml_results?hl=en#wsInterfaceLanguages) + proxy_location: (str): Where to get news, specifically for a specific country results. + ['US', 'CA', 'IE', 'GB', 'FR', 'DE', 'SE', 'IN', 'JP', 'KR', 'SG', 'AU', 'BR'] (defaults to US) + """ + super().__init__(**kwargs) + self.hl = hl + self.proxy_location = proxy_location + self.headers = { + "X-API-KEY": os.environ["SERPLY_API_KEY"], + "User-Agent": "crew-tools", + "X-Proxy-Location": proxy_location + } + + def _run( + self, + **kwargs: Any, + ) -> Any: + query_payload = { + "hl": self.hl + } + + if "query" in kwargs: + query_payload["q"] = kwargs["query"] + elif "search_query" in kwargs: + query_payload["q"] = kwargs["search_query"] + + # build the url + url = f"{self.search_url}{urlencode(query_payload)}" + + response = requests.request("GET", url, headers=self.headers) + articles = response.json().get("articles", "") + + if not articles: + return "" + + string = [] + for article in articles: + try: + if "doc" in article: + link = article['doc']['link'] + else: + link = article['link'] + authors = [author['name'] for author in article['author']['authors']] + string.append('\n'.join([ + f"Title: {article['title']}", + f"Link: {link}", + f"Description: {article['description']}", + f"Cite: {article['cite']}", + f"Authors: {', '.join(authors)}", + "---" + ])) + except KeyError: + next + + content = '\n'.join(string) + return f"\nSearch results: {content}\n" diff --git a/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py new file mode 100644 index 000000000..5f146c673 --- /dev/null +++ b/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py @@ -0,0 +1,93 @@ +import os +import requests +from urllib.parse import urlencode +from typing import Type, Any, Optional +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.base_tool import BaseTool + + +class SerplyWebSearchToolSchema(BaseModel): + """Input for Serply Web Search.""" + search_query: str = Field(..., description="Mandatory search query you want to use to Google search") + + +class SerplyWebSearchTool(BaseTool): + name: str = "Google Search" + description: str = "A tool to perform Google search with a search_query." + args_schema: Type[BaseModel] = SerplyWebSearchToolSchema + search_url: str = "https://api.serply.io/v1/search/" + hl: Optional[str] = "us" + limit: Optional[int] = 10 + device_type: Optional[str] = "desktop" + proxy_location: Optional[str] = "US" + query_payload: Optional[dict] = {} + headers: Optional[dict] = {} + + def __init__( + self, + hl: str = "us", + limit: int = 10, + device_type: str = "desktop", + proxy_location: str = "US", + **kwargs + ): + """ + param: query (str): The query to search for + param: hl (str): host Language code to display results in + (reference https://developers.google.com/custom-search/docs/xml_results?hl=en#wsInterfaceLanguages) + param: limit (int): The maximum number of results to return [10-100, defaults to 10] + param: device_type (str): desktop/mobile results (defaults to desktop) + proxy_location: (str): Where to perform the search, specifically for local/regional results. + ['US', 'CA', 'IE', 'GB', 'FR', 'DE', 'SE', 'IN', 'JP', 'KR', 'SG', 'AU', 'BR'] (defaults to US) + """ + super().__init__(**kwargs) + + self.limit = limit + self.device_type = device_type + self.proxy_location = proxy_location + + # build query parameters + self.query_payload = { + "num": limit, + "gl": proxy_location.upper(), + "hl": hl.lower() + } + self.headers = { + "X-API-KEY": os.environ["SERPLY_API_KEY"], + "X-User-Agent": device_type, + "User-Agent": "crew-tools", + "X-Proxy-Location": proxy_location + } + + def _run( + self, + **kwargs: Any, + ) -> Any: + if "query" in kwargs: + self.query_payload["q"] = kwargs["query"] + elif "search_query" in kwargs: + self.query_payload["q"] = kwargs["search_query"] + + # build the url + url = f"{self.search_url}{urlencode(self.query_payload)}" + + response = requests.request("GET", url, headers=self.headers) + results = response.json() + if "results" in results: + results = results['results'] + string = [] + for result in results: + try: + string.append('\n'.join([ + f"Title: {result['title']}", + f"Link: {result['link']}", + f"Description: {result['description'].strip()}", + "---" + ])) + except KeyError: + next + + content = '\n'.join(string) + return f"\nSearch results: {content}\n" + else: + return results From ffe3829ceff593cfbe2f398bf12051b9ca39e80c Mon Sep 17 00:00:00 2001 From: teampen <136991215+teampen@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:34:53 -0400 Subject: [PATCH 19/62] adding webpage to markdown --- src/crewai_tools/__init__.py | 3 +- src/crewai_tools/tools/__init__.py | 1 + .../tools/serply_api_tool/README.md | 39 +++++++++++++++ .../serply_news_search_tool.py | 1 + .../serply_scholar_search_tool.py | 5 +- .../serply_web_to_markdown_tool.py | 49 +++++++++++++++++++ 6 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index a9013b7ee..beb228936 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -25,5 +25,6 @@ from .tools import ( YoutubeVideoSearchTool, SerplyWebSearchTool, SerplyNewsSearchTool, - SerplyScholarSearchTool + SerplyScholarSearchTool, + SerplyWebpageToMarkdownTool ) \ No newline at end of file diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 138dbce17..11ceebfaa 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -24,3 +24,4 @@ from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSea from .serply_api_tool.serply_web_search_tool import SerplyWebSearchTool from .serply_api_tool.serply_news_search_tool import SerplyNewsSearchTool from .serply_api_tool.serply_scholar_search_tool import SerplyScholarSearchTool +from .serply_api_tool.serply_web_to_markdown_tool import SerplyWebpageToMarkdownTool diff --git a/src/crewai_tools/tools/serply_api_tool/README.md b/src/crewai_tools/tools/serply_api_tool/README.md index fe439b28f..22292bcf7 100644 --- a/src/crewai_tools/tools/serply_api_tool/README.md +++ b/src/crewai_tools/tools/serply_api_tool/README.md @@ -55,6 +55,45 @@ tool = SerplyScholarSearchTool() tool = SerplyScholarSearchTool(proxy_location="GB") ``` +## Web Page To Markdown +The following example demonstrates how to initialize the tool and fetch a web page and convert it to markdown: + +```python +from crewai_tools import SerplyWebpageToMarkdownTool + +# Initialize the tool for internet searching capabilities +tool = SerplyWebpageToMarkdownTool() + +# change country news (DE - Germany) +tool = SerplyWebpageToMarkdownTool(proxy_location="DE") +``` + +## Combining Multiple Tools + +The following example demonstrates performing a Google search to find relevant articles. Then, convert those articles to markdown format for easier extraction of key points. + +```python +from crewai import Agent +from crewai_tools import SerplyWebSearchTool, SerplyWebpageToMarkdownTool + +search_tool = SerplyWebSearchTool() +convert_to_markdown = SerplyWebpageToMarkdownTool() + +# Creating a senior researcher agent with memory and verbose mode +researcher = Agent( + role='Senior Researcher', + goal='Uncover groundbreaking technologies in {topic}', + verbose=True, + memory=True, + backstory=( + "Driven by curiosity, you're at the forefront of" + "innovation, eager to explore and share knowledge that could change" + "the world." + ), + tools=[search_tool, convert_to_markdown], + allow_delegation=True +) +``` ## Steps to Get Started To effectively use the `SerplyApiTool`, follow these steps: diff --git a/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py index c1fef5a77..40b1415b7 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py @@ -5,6 +5,7 @@ from typing import Type, Any, Optional from pydantic.v1 import BaseModel, Field from crewai_tools.tools.base_tool import BaseTool + class SerplyNewsSearchToolSchema(BaseModel): """Input for Serply News Search.""" search_query: str = Field(..., description="Mandatory search query you want to use to fetch news articles") diff --git a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py index badc9950e..dc7449353 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py @@ -5,6 +5,7 @@ from typing import Type, Any, Optional from pydantic.v1 import BaseModel, Field from crewai_tools.tools.base_tool import BaseTool + class SerplyScholarSearchToolSchema(BaseModel): """Input for Serply Scholar Search.""" search_query: str = Field(..., description="Mandatory search query you want to use to fetch scholarly literature") @@ -41,8 +42,8 @@ class SerplyScholarSearchTool(BaseTool): } def _run( - self, - **kwargs: Any, + self, + **kwargs: Any, ) -> Any: query_payload = { "hl": self.hl diff --git a/src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py new file mode 100644 index 000000000..36a42a48f --- /dev/null +++ b/src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py @@ -0,0 +1,49 @@ +import os +import requests +from urllib.parse import urlencode +from typing import Type, Any, Optional +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.rag.rag_tool import RagTool + + +class SerplyWebpageToMarkdownToolSchema(BaseModel): + """Input for Serply Scholar Search.""" + url: str = Field(..., description="Mandatory url you want to use to fetch and convert to markdown") + + +class SerplyWebpageToMarkdownTool(RagTool): + name: str = "Webpage to Markdown" + description: str = "A tool to perform convert a webpage to markdown to make it easier for LLMs to understand" + args_schema: Type[BaseModel] = SerplyWebpageToMarkdownToolSchema + request_url: str = "https://api.serply.io/v1/request" + proxy_location: Optional[str] = "US" + headers: Optional[dict] = {} + + def __init__( + self, + proxy_location: Optional[str] = "US", + **kwargs + ): + """ + proxy_location: (str): Where to get news, specifically for a specific country results. + ['US', 'CA', 'IE', 'GB', 'FR', 'DE', 'SE', 'IN', 'JP', 'KR', 'SG', 'AU', 'BR'] (defaults to US) + """ + super().__init__(**kwargs) + self.proxy_location = proxy_location + self.headers = { + "X-API-KEY": os.environ["SERPLY_API_KEY"], + "User-Agent": "crew-tools", + "X-Proxy-Location": proxy_location + } + + def _run( + self, + **kwargs: Any, + ) -> Any: + data = { + "url": kwargs["url"], + "method": "get", + "response_type": "markdown" + } + response = requests.request("POST", self.request_url, headers=self.headers, json=data) + return response.text From 2c0f90dd22cef5bb9fa1de9b13b5aba4ba6f4d54 Mon Sep 17 00:00:00 2001 From: teampen <136991215+teampen@users.noreply.github.com> Date: Tue, 11 Jun 2024 13:03:17 -0400 Subject: [PATCH 20/62] adding serply job search tool --- src/crewai_tools/__init__.py | 3 +- src/crewai_tools/tools/__init__.py | 3 +- .../tools/serply_api_tool/README.md | 13 +++- .../serply_api_tool/serply_job_search_tool.py | 75 +++++++++++++++++++ ....py => serply_webpage_to_markdown_tool.py} | 1 - 5 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py rename src/crewai_tools/tools/serply_api_tool/{serply_web_to_markdown_tool.py => serply_webpage_to_markdown_tool.py} (97%) diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index beb228936..ec5abc1ce 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -26,5 +26,6 @@ from .tools import ( SerplyWebSearchTool, SerplyNewsSearchTool, SerplyScholarSearchTool, - SerplyWebpageToMarkdownTool + SerplyWebpageToMarkdownTool, + SerplyJobSearchTool ) \ No newline at end of file diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 11ceebfaa..151401647 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -24,4 +24,5 @@ from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSea from .serply_api_tool.serply_web_search_tool import SerplyWebSearchTool from .serply_api_tool.serply_news_search_tool import SerplyNewsSearchTool from .serply_api_tool.serply_scholar_search_tool import SerplyScholarSearchTool -from .serply_api_tool.serply_web_to_markdown_tool import SerplyWebpageToMarkdownTool +from .serply_api_tool.serply_webpage_to_markdown_tool import SerplyWebpageToMarkdownTool +from .serply_api_tool.serply_job_search_tool import SerplyJobSearchTool diff --git a/src/crewai_tools/tools/serply_api_tool/README.md b/src/crewai_tools/tools/serply_api_tool/README.md index 22292bcf7..5c6b9395e 100644 --- a/src/crewai_tools/tools/serply_api_tool/README.md +++ b/src/crewai_tools/tools/serply_api_tool/README.md @@ -55,6 +55,17 @@ tool = SerplyScholarSearchTool() tool = SerplyScholarSearchTool(proxy_location="GB") ``` +## Job Search +The following example demonstrates how to initialize the tool and searching for jobs in the USA: + +```python +from crewai_tools import SerplyJobSearchTool + +# Initialize the tool for internet searching capabilities +tool = SerplyJobSearchTool() +``` + + ## Web Page To Markdown The following example demonstrates how to initialize the tool and fetch a web page and convert it to markdown: @@ -64,7 +75,7 @@ from crewai_tools import SerplyWebpageToMarkdownTool # Initialize the tool for internet searching capabilities tool = SerplyWebpageToMarkdownTool() -# change country news (DE - Germany) +# change country make request from (DE - Germany) tool = SerplyWebpageToMarkdownTool(proxy_location="DE") ``` diff --git a/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py new file mode 100644 index 000000000..1013c3d47 --- /dev/null +++ b/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py @@ -0,0 +1,75 @@ +import os +import requests +from urllib.parse import urlencode +from typing import Type, Any, Optional +from pydantic.v1 import BaseModel, Field +from crewai_tools.tools.rag.rag_tool import RagTool + + +class SerplyJobSearchToolSchema(BaseModel): + """Input for Serply Scholar Search.""" + search_query: str = Field(..., description="Mandatory search query you want to use to fetch jobs postings.") + + +class SerplyJobSearchTool(RagTool): + name: str = "Job Search" + description: str = "A tool to perform to perform a job search in the US with a search_query." + args_schema: Type[BaseModel] = SerplyJobSearchToolSchema + request_url: str = "https://api.serply.io/v1/job/search/" + proxy_location: Optional[str] = "US" + """ + proxy_location: (str): Where to get news, specifically for a specific country results. + - Currently only supports US + """ + headers: Optional[dict] = {} + + def __init__( + self, + **kwargs + ): + super().__init__(**kwargs) + self.headers = { + "X-API-KEY": os.environ["SERPLY_API_KEY"], + "User-Agent": "crew-tools", + "X-Proxy-Location": self.proxy_location + } + + def _run( + self, + **kwargs: Any, + ) -> Any: + query_payload = {} + + if "query" in kwargs: + query_payload["q"] = kwargs["query"] + elif "search_query" in kwargs: + query_payload["q"] = kwargs["search_query"] + + # build the url + url = f"{self.request_url}{urlencode(query_payload)}" + + response = requests.request("GET", url, headers=self.headers) + + jobs = response.json().get("jobs", "") + + if not jobs: + return "" + + string = [] + for job in jobs: + try: + string.append('\n'.join([ + f"Position: {job['position']}", + f"Employer: {job['employer']}", + f"Location: {job['location']}", + f"Link: {job['link']}", + f"""Highest: {', '.join([h for h in job['highlights']])}""", + f"Is Remote: {job['is_remote']}", + f"Is Hybrid: {job['is_remote']}", + "---" + ])) + except KeyError: + next + + content = '\n'.join(string) + return f"\nSearch results: {content}\n" diff --git a/src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py similarity index 97% rename from src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py rename to src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py index 36a42a48f..c7692a066 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_web_to_markdown_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py @@ -1,6 +1,5 @@ import os import requests -from urllib.parse import urlencode from typing import Type, Any, Optional from pydantic.v1 import BaseModel, Field from crewai_tools.tools.rag.rag_tool import RagTool From 5e8e711170f8b003e65a46dc141f3974621dca9f Mon Sep 17 00:00:00 2001 From: Rip&Tear <84775494+theCyberTech@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:53:35 +0800 Subject: [PATCH 21/62] Update serper_dev_tool.py Added two additional functionalities: 1) added the ability to save the server results to a file 2) added the ability to set the number of results returned Can be used as follows: serper_tool = SerperDevTool(file_save=True, n_results=20) --- .../tools/serper_dev_tool/serper_dev_tool.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py index 927c0e3b3..bd6eaab54 100644 --- a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py +++ b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py @@ -6,6 +6,14 @@ from typing import Type, Any from pydantic.v1 import BaseModel, Field from crewai_tools.tools.base_tool import BaseTool +def _save_results_to_file(content: str) -> None: + """Saves the search results to a file.""" + filename = f"search_results_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt" + with open(filename, 'w') as file: + file.write(content) + print(f"Results saved to {filename}") + + class SerperDevToolSchema(BaseModel): """Input for SerperDevTool.""" search_query: str = Field(..., description="Mandatory search query you want to use to search the internet") @@ -15,17 +23,22 @@ class SerperDevTool(BaseTool): description: str = "A tool that can be used to search the internet with a search_query." args_schema: Type[BaseModel] = SerperDevToolSchema search_url: str = "https://google.serper.dev/search" - n_results: int = 10 + n_results: int = Field(default=10, description="Number of search results to return") + save_file: bool = Field(default=False, description="Flag to determine whether to save the results to a file") def _run( self, **kwargs: Any, ) -> Any: + save_file = kwargs.get('save_file', self.save_file) + + n_results = kwargs.get('n_results', self.n_results) + search_query = kwargs.get('search_query') if search_query is None: search_query = kwargs.get('query') - payload = json.dumps({"q": search_query}) + payload = json.dumps({"q": search_query, "num": n_results}) headers = { 'X-API-KEY': os.environ['SERPER_API_KEY'], 'content-type': 'application/json' @@ -47,6 +60,8 @@ class SerperDevTool(BaseTool): next content = '\n'.join(string) + if save_file: + _save_results_to_file(content) return f"\nSearch results: {content}\n" else: return results From 806f88495668724ee847155c7232041844bcb8a5 Mon Sep 17 00:00:00 2001 From: teampen <136991215+teampen@users.noreply.github.com> Date: Fri, 14 Jun 2024 01:43:25 +0000 Subject: [PATCH 22/62] using GET in markdown --- .../tools/serply_api_tool/serply_job_search_tool.py | 4 ++-- .../tools/serply_api_tool/serply_news_search_tool.py | 2 +- .../tools/serply_api_tool/serply_scholar_search_tool.py | 2 +- .../tools/serply_api_tool/serply_web_search_tool.py | 2 +- .../tools/serply_api_tool/serply_webpage_to_markdown_tool.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py index 1013c3d47..358e312c7 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py @@ -18,7 +18,7 @@ class SerplyJobSearchTool(RagTool): request_url: str = "https://api.serply.io/v1/job/search/" proxy_location: Optional[str] = "US" """ - proxy_location: (str): Where to get news, specifically for a specific country results. + proxy_location: (str): Where to get jobs, specifically for a specific country results. - Currently only supports US """ headers: Optional[dict] = {} @@ -69,7 +69,7 @@ class SerplyJobSearchTool(RagTool): "---" ])) except KeyError: - next + continue content = '\n'.join(string) return f"\nSearch results: {content}\n" diff --git a/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py index 40b1415b7..f1127246e 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_news_search_tool.py @@ -73,7 +73,7 @@ class SerplyNewsSearchTool(BaseTool): "---" ])) except KeyError: - next + continue content = '\n'.join(string) return f"\nSearch results: {content}\n" diff --git a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py index dc7449353..62c3bef7f 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py @@ -80,7 +80,7 @@ class SerplyScholarSearchTool(BaseTool): "---" ])) except KeyError: - next + continue content = '\n'.join(string) return f"\nSearch results: {content}\n" diff --git a/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py index 5f146c673..894c24741 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_web_search_tool.py @@ -85,7 +85,7 @@ class SerplyWebSearchTool(BaseTool): "---" ])) except KeyError: - next + continue content = '\n'.join(string) return f"\nSearch results: {content}\n" diff --git a/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py index c7692a066..27ffc54ce 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py @@ -41,7 +41,7 @@ class SerplyWebpageToMarkdownTool(RagTool): ) -> Any: data = { "url": kwargs["url"], - "method": "get", + "method": "GET", "response_type": "markdown" } response = requests.request("POST", self.request_url, headers=self.headers, json=data) From 2b47377a7849be73c8ecac19338aaa7811bdbd27 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Wed, 19 Jun 2024 20:45:04 -0300 Subject: [PATCH 23/62] feat: add code-interpreter tool --- .../tools/code_interpreter_tool/Dockerfile | 21 +++++++ .../tools/code_interpreter_tool/README.md | 0 .../code_interpreter_tool.py | 57 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/crewai_tools/tools/code_interpreter_tool/Dockerfile create mode 100644 src/crewai_tools/tools/code_interpreter_tool/README.md create mode 100644 src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py diff --git a/src/crewai_tools/tools/code_interpreter_tool/Dockerfile b/src/crewai_tools/tools/code_interpreter_tool/Dockerfile new file mode 100644 index 000000000..b72a51a88 --- /dev/null +++ b/src/crewai_tools/tools/code_interpreter_tool/Dockerfile @@ -0,0 +1,21 @@ +# Use an official Ubuntu as a parent image +FROM ubuntu:20.04 + +# Set environment variables +ENV DEBIAN_FRONTEND=noninteractive + +# Install common utilities +RUN apt-get update && apt-get install -y \ + build-essential \ + curl \ + wget \ + software-properties-common + +# Install Python +RUN apt-get install -y python3 python3-pip + +# Clean up +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + +# Set the working directory +WORKDIR /workspace diff --git a/src/crewai_tools/tools/code_interpreter_tool/README.md b/src/crewai_tools/tools/code_interpreter_tool/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py new file mode 100644 index 000000000..a2066ca03 --- /dev/null +++ b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py @@ -0,0 +1,57 @@ +from typing import Optional, Type + +import docker +from crewai_tools.tools.base_tool import BaseTool +from pydantic.v1 import BaseModel, Field + + +class FixedCodeInterpreterSchemaSchema(BaseModel): + """Input for DirectoryReadTool.""" + + pass + + +class CodeInterpreterSchema(FixedCodeInterpreterSchemaSchema): + """Input for DirectoryReadTool.""" + + code: str = Field( + ..., + description="Python3 code used to be interpreted in the Docker container and output the result", + ) + + +class CodeInterpreterTool(BaseTool): + name: str = "Code Interpreter" + description: str = "Interprets Python code in a Docker container" + args_schema: Type[BaseModel] = CodeInterpreterSchema + code: Optional[str] = None + + def __init__(self, code: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + if code is not None: + self.code = code + self.description = ( + "A tool that can be used to run Python code in a Docker container" + ) + self.args_schema = FixedCodeInterpreterSchemaSchema + self._generate_description() + + def _run(self, **kwargs): + code = kwargs.get("code", self.code) + return self.run_code_in_docker(code) + + def run_code_in_docker(self, code): + client = docker.from_env() + container = client.containers.run( + "code-interpreter", + command=f'python3 -c "{code}"', + detach=True, + working_dir="/workspace", + ) + + result = container.logs().decode("utf-8") + + container.stop() + container.remove() + + return result From bd13b55afd229fa830a944063fa90b33a2371b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Mon, 20 May 2024 11:02:20 -0300 Subject: [PATCH 24/62] Adding new PDFTextWritingTool --- .../pdf_text_writing_tool.py | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/crewai_tools/tools/pdf_text_writing_tool/pdf_text_writing_tool.py diff --git a/src/crewai_tools/tools/pdf_text_writing_tool/pdf_text_writing_tool.py b/src/crewai_tools/tools/pdf_text_writing_tool/pdf_text_writing_tool.py new file mode 100644 index 000000000..c3a686b14 --- /dev/null +++ b/src/crewai_tools/tools/pdf_text_writing_tool/pdf_text_writing_tool.py @@ -0,0 +1,66 @@ +from typing import Any, Optional, Type +from pydantic import BaseModel, Field +from pypdf import PdfReader, PdfWriter, PageObject, ContentStream, NameObject, Font +from pathlib import Path + + +class PDFTextWritingToolSchema(BaseModel): + """Input schema for PDFTextWritingTool.""" + pdf_path: str = Field(..., description="Path to the PDF file to modify") + text: str = Field(..., description="Text to add to the PDF") + position: tuple = Field(..., description="Tuple of (x, y) coordinates for text placement") + font_size: int = Field(default=12, description="Font size of the text") + font_color: str = Field(default="0 0 0 rg", description="RGB color code for the text") + font_name: Optional[str] = Field(default="F1", description="Font name for standard fonts") + font_file: Optional[str] = Field(None, description="Path to a .ttf font file for custom font usage") + page_number: int = Field(default=0, description="Page number to add text to") + + +class PDFTextWritingTool(RagTool): + """A tool to add text to specific positions in a PDF, with custom font support.""" + name: str = "PDF Text Writing Tool" + description: str = "A tool that can write text to a specific position in a PDF document, with optional custom font embedding." + args_schema: Type[BaseModel] = PDFTextWritingToolSchema + + def run(self, pdf_path: str, text: str, position: tuple, font_size: int, font_color: str, + font_name: str = "F1", font_file: Optional[str] = None, page_number: int = 0, **kwargs) -> str: + reader = PdfReader(pdf_path) + writer = PdfWriter() + + if page_number >= len(reader.pages): + return "Page number out of range." + + page: PageObject = reader.pages[page_number] + content = ContentStream(page["/Contents"].data, reader) + + if font_file: + # Check if the font file exists + if not Path(font_file).exists(): + return "Font file does not exist." + + # Embed the custom font + font_name = self.embed_font(writer, font_file) + + # Prepare text operation with the custom or standard font + x_position, y_position = position + text_operation = f"BT /{font_name} {font_size} Tf {x_position} {y_position} Td ({text}) Tj ET" + content.operations.append([font_color]) # Set color + content.operations.append([text_operation]) # Add text + + # Replace old content with new content + page[NameObject("/Contents")] = content + writer.add_page(page) + + # Save the new PDF + output_pdf_path = "modified_output.pdf" + with open(output_pdf_path, "wb") as out_file: + writer.write(out_file) + + return f"Text added to {output_pdf_path} successfully." + + def embed_font(self, writer: PdfWriter, font_file: str) -> str: + """Embeds a TTF font into the PDF and returns the font name.""" + with open(font_file, "rb") as file: + font = Font.true_type(file.read()) + font_ref = writer.add_object(font) + return font_ref \ No newline at end of file From da75d51fe8431aae6b7333cdeee0ecf5d9e91843 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 20 Jun 2024 20:24:26 -0300 Subject: [PATCH 25/62] feat: add Dockerfile, Makefile and update version of code --- .../tools/code_interpreter_tool/Dockerfile | 9 +--- .../tools/code_interpreter_tool/Makefile | 6 +++ .../code_interpreter_tool.py | 51 ++++++++++++------- 3 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 src/crewai_tools/tools/code_interpreter_tool/Makefile diff --git a/src/crewai_tools/tools/code_interpreter_tool/Dockerfile b/src/crewai_tools/tools/code_interpreter_tool/Dockerfile index b72a51a88..ae9b2ffd6 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/Dockerfile +++ b/src/crewai_tools/tools/code_interpreter_tool/Dockerfile @@ -1,8 +1,4 @@ -# Use an official Ubuntu as a parent image -FROM ubuntu:20.04 - -# Set environment variables -ENV DEBIAN_FRONTEND=noninteractive +FROM python:3.11-slim # Install common utilities RUN apt-get update && apt-get install -y \ @@ -11,9 +7,6 @@ RUN apt-get update && apt-get install -y \ wget \ software-properties-common -# Install Python -RUN apt-get install -y python3 python3-pip - # Clean up RUN apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/src/crewai_tools/tools/code_interpreter_tool/Makefile b/src/crewai_tools/tools/code_interpreter_tool/Makefile new file mode 100644 index 000000000..5a514db0a --- /dev/null +++ b/src/crewai_tools/tools/code_interpreter_tool/Makefile @@ -0,0 +1,6 @@ +# Makefile +IMAGE_NAME=code-interpreter +TAG=latest + +build: + docker build -t $(IMAGE_NAME):$(TAG) . diff --git a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py index a2066ca03..f497a7c96 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py +++ b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py @@ -6,23 +6,27 @@ from pydantic.v1 import BaseModel, Field class FixedCodeInterpreterSchemaSchema(BaseModel): - """Input for DirectoryReadTool.""" + """Input for CodeInterpreterTool.""" pass class CodeInterpreterSchema(FixedCodeInterpreterSchemaSchema): - """Input for DirectoryReadTool.""" + """Input for CodeInterpreterTool.""" code: str = Field( ..., - description="Python3 code used to be interpreted in the Docker container and output the result", + description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code", + ) + libraries_used: Optional[str] = Field( + None, + description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4", ) class CodeInterpreterTool(BaseTool): name: str = "Code Interpreter" - description: str = "Interprets Python code in a Docker container" + description: str = "Interprets Python code in a Docker container. ALWAYS PRINT the final result and the output of the code" args_schema: Type[BaseModel] = CodeInterpreterSchema code: Optional[str] = None @@ -30,28 +34,41 @@ class CodeInterpreterTool(BaseTool): super().__init__(**kwargs) if code is not None: self.code = code - self.description = ( - "A tool that can be used to run Python code in a Docker container" - ) + self.description = "Interprets Python code in a Docker container. ALWAYS PRINT the final result and the output of the code" self.args_schema = FixedCodeInterpreterSchemaSchema self._generate_description() def _run(self, **kwargs): code = kwargs.get("code", self.code) - return self.run_code_in_docker(code) + libraries_used = kwargs.get("libraries_used", None) + return self.run_code_in_docker(code, libraries_used) - def run_code_in_docker(self, code): + def run_code_in_docker(self, code, libraries_used): client = docker.from_env() - container = client.containers.run( - "code-interpreter", - command=f'python3 -c "{code}"', - detach=True, - working_dir="/workspace", - ) - result = container.logs().decode("utf-8") + def run_code(container, code): + cmd_to_run = f'python3 -c "{code}"' + exec_result = container.exec_run(cmd_to_run) + return exec_result + + container = client.containers.run( + "code-interpreter", detach=True, tty=True, working_dir="/workspace" + ) + if libraries_used: + self._install_libraries(container, libraries_used.split(",")) + + exec_result = run_code(container, code) container.stop() container.remove() + if exec_result.exit_code != 0: + return f"Something went wrong while running the code: \n{exec_result.output.decode('utf-8')}" - return result + return exec_result.output.decode("utf-8") + + def _install_libraries(self, container, libraries): + """ + Install missing libraries in the Docker container + """ + for library in libraries: + container.exec_run(f"pip install {library}") From 1a4ac76b1eb11ec70a11784a4f6b1d33948e9171 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 20 Jun 2024 20:24:47 -0300 Subject: [PATCH 26/62] feat: update code --- .../code_interpreter_tool.py | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py index f497a7c96..caafd44e3 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py +++ b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py @@ -30,7 +30,7 @@ class CodeInterpreterTool(BaseTool): args_schema: Type[BaseModel] = CodeInterpreterSchema code: Optional[str] = None - def __init__(self, code: Optional[str] = None, **kwargs): + def __init__(self, code: Optional[str] = None, **kwargs) -> None: super().__init__(**kwargs) if code is not None: self.code = code @@ -38,37 +38,37 @@ class CodeInterpreterTool(BaseTool): self.args_schema = FixedCodeInterpreterSchemaSchema self._generate_description() - def _run(self, **kwargs): + def _run(self, **kwargs) -> str: code = kwargs.get("code", self.code) libraries_used = kwargs.get("libraries_used", None) return self.run_code_in_docker(code, libraries_used) - def run_code_in_docker(self, code, libraries_used): - client = docker.from_env() - - def run_code(container, code): - cmd_to_run = f'python3 -c "{code}"' - exec_result = container.exec_run(cmd_to_run) - return exec_result - - container = client.containers.run( - "code-interpreter", detach=True, tty=True, working_dir="/workspace" - ) - if libraries_used: - self._install_libraries(container, libraries_used.split(",")) - - exec_result = run_code(container, code) - - container.stop() - container.remove() - if exec_result.exit_code != 0: - return f"Something went wrong while running the code: \n{exec_result.output.decode('utf-8')}" - - return exec_result.output.decode("utf-8") - - def _install_libraries(self, container, libraries): + def _install_libraries( + self, container: docker.models.containers.Container, libraries: list[str] + ) -> None: """ Install missing libraries in the Docker container """ for library in libraries: container.exec_run(f"pip install {library}") + + def _init_docker_container(self) -> docker.models.containers.Container: + client = docker.from_env() + return client.containers.run( + "code-interpreter", detach=True, tty=True, working_dir="/workspace" + ) + + def run_code_in_docker(self, code: str, libraries_used: str) -> str: + container = self._init_docker_container() + + if libraries_used: + self._install_libraries(container, libraries_used.split(",")) + + cmd_to_run = f'python3 -c "{code}"' + exec_result = container.exec_run(cmd_to_run) + + container.stop().remove() + + if exec_result.exit_code != 0: + return f"Something went wrong while running the code: \n{exec_result.output.decode('utf-8')}" + return exec_result.output.decode("utf-8") From 94e6651b55cbebd85b0610787de5f4429e0778b1 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 20 Jun 2024 20:43:19 -0300 Subject: [PATCH 27/62] feat: add code-interpreter tool to init and add unit tests --- src/crewai_tools/tools/__init__.py | 17 ++++++---- tests/tools/test_code_interpreter_tool.py | 38 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 tests/tools/test_code_interpreter_tool.py diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 4da0c0337..35b81396b 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -1,24 +1,29 @@ from .browserbase_load_tool.browserbase_load_tool import BrowserbaseLoadTool from .code_docs_search_tool.code_docs_search_tool import CodeDocsSearchTool +from .code_interpreter_tool.code_interpreter_tool import CodeInterpreterTool from .csv_search_tool.csv_search_tool import CSVSearchTool -from .directory_search_tool.directory_search_tool import DirectorySearchTool from .directory_read_tool.directory_read_tool import DirectoryReadTool +from .directory_search_tool.directory_search_tool import DirectorySearchTool from .docx_search_tool.docx_search_tool import DOCXSearchTool from .exa_tools.exa_search_tool import EXASearchTool from .file_read_tool.file_read_tool import FileReadTool from .github_search_tool.github_search_tool import GithubSearchTool -from .serper_dev_tool.serper_dev_tool import SerperDevTool -from .txt_search_tool.txt_search_tool import TXTSearchTool from .json_search_tool.json_search_tool import JSONSearchTool +from .llamaindex_tool.llamaindex_tool import LlamaIndexTool from .mdx_seach_tool.mdx_search_tool import MDXSearchTool from .pdf_search_tool.pdf_search_tool import PDFSearchTool from .pg_seach_tool.pg_search_tool import PGSearchTool from .rag.rag_tool import RagTool -from .scrape_element_from_website.scrape_element_from_website import ScrapeElementFromWebsiteTool +from .scrape_element_from_website.scrape_element_from_website import ( + ScrapeElementFromWebsiteTool, +) from .scrape_website_tool.scrape_website_tool import ScrapeWebsiteTool from .selenium_scraping_tool.selenium_scraping_tool import SeleniumScrapingTool +from .serper_dev_tool.serper_dev_tool import SerperDevTool +from .txt_search_tool.txt_search_tool import TXTSearchTool from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool -from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool +from .youtube_channel_search_tool.youtube_channel_search_tool import ( + YoutubeChannelSearchTool, +) from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool -from .llamaindex_tool.llamaindex_tool import LlamaIndexTool diff --git a/tests/tools/test_code_interpreter_tool.py b/tests/tools/test_code_interpreter_tool.py new file mode 100644 index 000000000..a9ffb9dbc --- /dev/null +++ b/tests/tools/test_code_interpreter_tool.py @@ -0,0 +1,38 @@ +import unittest +from unittest.mock import patch + +from crewai_tools.tools.code_interpreter_tool.code_interpreter_tool import ( + CodeInterpreterTool, +) + + +class TestCodeInterpreterTool(unittest.TestCase): + @patch("crewai_tools.tools.code_interpreter_tool.code_interpreter_tool.docker") + def test_run_code_in_docker(self, docker_mock): + tool = CodeInterpreterTool() + code = "print('Hello, World!')" + libraries_used = "numpy,pandas" + expected_output = "Hello, World!\n" + + docker_mock.from_env().containers.run().exec_run().exit_code = 0 + docker_mock.from_env().containers.run().exec_run().output = ( + expected_output.encode() + ) + result = tool.run_code_in_docker(code, libraries_used) + + self.assertEqual(result, expected_output) + + @patch("crewai_tools.tools.code_interpreter_tool.code_interpreter_tool.docker") + def test_run_code_in_docker_with_error(self, docker_mock): + tool = CodeInterpreterTool() + code = "print(1/0)" + libraries_used = "numpy,pandas" + expected_output = "Something went wrong while running the code: \nZeroDivisionError: division by zero\n" + + docker_mock.from_env().containers.run().exec_run().exit_code = 1 + docker_mock.from_env().containers.run().exec_run().output = ( + b"ZeroDivisionError: division by zero\n" + ) + result = tool.run_code_in_docker(code, libraries_used) + + self.assertEqual(result, expected_output) From 61cce93fd020fa4fce74cc80f64e07f2a777215d Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 20 Jun 2024 21:41:12 -0300 Subject: [PATCH 28/62] feat: remove unused Makefile, update README and update code --- .../tools/code_interpreter_tool/Makefile | 6 ----- .../tools/code_interpreter_tool/README.md | 27 +++++++++++++++++++ .../code_interpreter_tool.py | 22 ++++++++++++++- 3 files changed, 48 insertions(+), 7 deletions(-) delete mode 100644 src/crewai_tools/tools/code_interpreter_tool/Makefile diff --git a/src/crewai_tools/tools/code_interpreter_tool/Makefile b/src/crewai_tools/tools/code_interpreter_tool/Makefile deleted file mode 100644 index 5a514db0a..000000000 --- a/src/crewai_tools/tools/code_interpreter_tool/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# Makefile -IMAGE_NAME=code-interpreter -TAG=latest - -build: - docker build -t $(IMAGE_NAME):$(TAG) . diff --git a/src/crewai_tools/tools/code_interpreter_tool/README.md b/src/crewai_tools/tools/code_interpreter_tool/README.md index e69de29bb..672c86f21 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/README.md +++ b/src/crewai_tools/tools/code_interpreter_tool/README.md @@ -0,0 +1,27 @@ +# CodeInterpreterTool + +## Description +This tool is used to give the Agent the ability to run code (Python3) from the code generated by the Agent itself. The code is executed in a sandboxed environment, so it is safe to run any code. + +## Requirements + +- Docker + +## Installation +Install the crewai_tools package +```shell +pip install 'crewai[tools]' +``` + +## Example + +Remember that when using this tool, the code must be generated by the Agent itself. The code must be a Python3 code. And it will take some time for the first time to run because it needs to build the Docker image. + +```python +from crewai_tools import CodeInterpreterTool + +Agent( + ... + tools=[CodeInterpreterTool()], +) +``` diff --git a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py index caafd44e3..06cb081f0 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py +++ b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py @@ -1,3 +1,4 @@ +import os from typing import Optional, Type import docker @@ -30,9 +31,27 @@ class CodeInterpreterTool(BaseTool): args_schema: Type[BaseModel] = CodeInterpreterSchema code: Optional[str] = None + def _verify_docker_image(self) -> None: + """ + Verify if the Docker image is available + """ + image_tag = "code-interpreter:latest" + + client = docker.from_env() + images = client.images.list() + all_tags = [tag for image in images for tag in image.tags] + + if image_tag not in all_tags: + client.images.build( + path=os.path.dirname(os.path.abspath(__file__)), + tag=image_tag, + rm=True, + ) + def __init__(self, code: Optional[str] = None, **kwargs) -> None: super().__init__(**kwargs) if code is not None: + self._verify_docker_image() self.code = code self.description = "Interprets Python code in a Docker container. ALWAYS PRINT the final result and the output of the code" self.args_schema = FixedCodeInterpreterSchemaSchema @@ -67,7 +86,8 @@ class CodeInterpreterTool(BaseTool): cmd_to_run = f'python3 -c "{code}"' exec_result = container.exec_run(cmd_to_run) - container.stop().remove() + container.stop() + container.remove() if exec_result.exit_code != 0: return f"Something went wrong while running the code: \n{exec_result.output.decode('utf-8')}" From 161c72b29f553f6b3758b9408ff9423349c5bba7 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 20 Jun 2024 21:55:25 -0300 Subject: [PATCH 29/62] feat: update README --- src/crewai_tools/tools/code_interpreter_tool/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crewai_tools/tools/code_interpreter_tool/README.md b/src/crewai_tools/tools/code_interpreter_tool/README.md index 672c86f21..e66a82e39 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/README.md +++ b/src/crewai_tools/tools/code_interpreter_tool/README.md @@ -3,6 +3,8 @@ ## Description This tool is used to give the Agent the ability to run code (Python3) from the code generated by the Agent itself. The code is executed in a sandboxed environment, so it is safe to run any code. +It is incredible useful since it allows the Agent to generate code, run it in the same environment, get the result and use it to make decisions. + ## Requirements - Docker From 2f80840c748e5b501bf688cff95713c1c5c18ac2 Mon Sep 17 00:00:00 2001 From: Jakub Strnad Date: Fri, 21 Jun 2024 15:06:17 +0200 Subject: [PATCH 30/62] fix: Ensure tools handle parameters passed post-creation correctly (#3) - Fixed an issue where multiple tools failed to function if parameters were provided after tool creation. - Updated tools to correctly process source file/URL passed by the agent post-creation as per documentation. Closes #<47> --- .../tools/code_docs_search_tool/code_docs_search_tool.py | 2 +- src/crewai_tools/tools/csv_search_tool/csv_search_tool.py | 2 +- .../tools/directory_search_tool/directory_search_tool.py | 2 +- src/crewai_tools/tools/docx_search_tool/docx_search_tool.py | 2 +- src/crewai_tools/tools/github_search_tool/github_search_tool.py | 2 +- src/crewai_tools/tools/json_search_tool/json_search_tool.py | 2 +- src/crewai_tools/tools/mdx_seach_tool/mdx_search_tool.py | 2 +- src/crewai_tools/tools/pg_seach_tool/pg_search_tool.py | 2 +- src/crewai_tools/tools/txt_search_tool/txt_search_tool.py | 2 +- src/crewai_tools/tools/website_search/website_search_tool.py | 2 +- src/crewai_tools/tools/xml_search_tool/xml_search_tool.py | 2 +- .../youtube_channel_search_tool/youtube_channel_search_tool.py | 2 +- .../youtube_video_search_tool/youtube_video_search_tool.py | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/crewai_tools/tools/code_docs_search_tool/code_docs_search_tool.py b/src/crewai_tools/tools/code_docs_search_tool/code_docs_search_tool.py index a69ea7eb4..899943511 100644 --- a/src/crewai_tools/tools/code_docs_search_tool/code_docs_search_tool.py +++ b/src/crewai_tools/tools/code_docs_search_tool/code_docs_search_tool.py @@ -57,4 +57,4 @@ class CodeDocsSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/csv_search_tool/csv_search_tool.py b/src/crewai_tools/tools/csv_search_tool/csv_search_tool.py index a04f227ca..9d0509f88 100644 --- a/src/crewai_tools/tools/csv_search_tool/csv_search_tool.py +++ b/src/crewai_tools/tools/csv_search_tool/csv_search_tool.py @@ -57,4 +57,4 @@ class CSVSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/directory_search_tool/directory_search_tool.py b/src/crewai_tools/tools/directory_search_tool/directory_search_tool.py index 9a988a7fa..a06229081 100644 --- a/src/crewai_tools/tools/directory_search_tool/directory_search_tool.py +++ b/src/crewai_tools/tools/directory_search_tool/directory_search_tool.py @@ -57,4 +57,4 @@ class DirectorySearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/docx_search_tool/docx_search_tool.py b/src/crewai_tools/tools/docx_search_tool/docx_search_tool.py index 96bb4721b..b60dfd0f5 100644 --- a/src/crewai_tools/tools/docx_search_tool/docx_search_tool.py +++ b/src/crewai_tools/tools/docx_search_tool/docx_search_tool.py @@ -63,4 +63,4 @@ class DOCXSearchTool(RagTool): docx = kwargs.get("docx") if docx is not None: self.add(docx) - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/github_search_tool/github_search_tool.py b/src/crewai_tools/tools/github_search_tool/github_search_tool.py index 5bfa65542..2ec39c8c0 100644 --- a/src/crewai_tools/tools/github_search_tool/github_search_tool.py +++ b/src/crewai_tools/tools/github_search_tool/github_search_tool.py @@ -68,4 +68,4 @@ class GithubSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/json_search_tool/json_search_tool.py b/src/crewai_tools/tools/json_search_tool/json_search_tool.py index 102cd89ad..930438c88 100644 --- a/src/crewai_tools/tools/json_search_tool/json_search_tool.py +++ b/src/crewai_tools/tools/json_search_tool/json_search_tool.py @@ -57,4 +57,4 @@ class JSONSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/mdx_seach_tool/mdx_search_tool.py b/src/crewai_tools/tools/mdx_seach_tool/mdx_search_tool.py index 99bd37348..69572140b 100644 --- a/src/crewai_tools/tools/mdx_seach_tool/mdx_search_tool.py +++ b/src/crewai_tools/tools/mdx_seach_tool/mdx_search_tool.py @@ -57,4 +57,4 @@ class MDXSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/pg_seach_tool/pg_search_tool.py b/src/crewai_tools/tools/pg_seach_tool/pg_search_tool.py index 226fb1ddd..6f9ea2901 100644 --- a/src/crewai_tools/tools/pg_seach_tool/pg_search_tool.py +++ b/src/crewai_tools/tools/pg_seach_tool/pg_search_tool.py @@ -41,4 +41,4 @@ class PGSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/txt_search_tool/txt_search_tool.py b/src/crewai_tools/tools/txt_search_tool/txt_search_tool.py index 921e633e8..5dbaed4d4 100644 --- a/src/crewai_tools/tools/txt_search_tool/txt_search_tool.py +++ b/src/crewai_tools/tools/txt_search_tool/txt_search_tool.py @@ -57,4 +57,4 @@ class TXTSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/website_search/website_search_tool.py b/src/crewai_tools/tools/website_search/website_search_tool.py index cfe163ae8..1ff587f00 100644 --- a/src/crewai_tools/tools/website_search/website_search_tool.py +++ b/src/crewai_tools/tools/website_search/website_search_tool.py @@ -57,4 +57,4 @@ class WebsiteSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/xml_search_tool/xml_search_tool.py b/src/crewai_tools/tools/xml_search_tool/xml_search_tool.py index 53fd73248..0346d484e 100644 --- a/src/crewai_tools/tools/xml_search_tool/xml_search_tool.py +++ b/src/crewai_tools/tools/xml_search_tool/xml_search_tool.py @@ -57,4 +57,4 @@ class XMLSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/youtube_channel_search_tool/youtube_channel_search_tool.py b/src/crewai_tools/tools/youtube_channel_search_tool/youtube_channel_search_tool.py index 8e9591be8..2edc0026b 100644 --- a/src/crewai_tools/tools/youtube_channel_search_tool/youtube_channel_search_tool.py +++ b/src/crewai_tools/tools/youtube_channel_search_tool/youtube_channel_search_tool.py @@ -60,4 +60,4 @@ class YoutubeChannelSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) diff --git a/src/crewai_tools/tools/youtube_video_search_tool/youtube_video_search_tool.py b/src/crewai_tools/tools/youtube_video_search_tool/youtube_video_search_tool.py index f1caa1b9c..77d25752e 100644 --- a/src/crewai_tools/tools/youtube_video_search_tool/youtube_video_search_tool.py +++ b/src/crewai_tools/tools/youtube_video_search_tool/youtube_video_search_tool.py @@ -57,4 +57,4 @@ class YoutubeVideoSearchTool(RagTool): search_query: str, **kwargs: Any, ) -> Any: - return super()._run(query=search_query) + return super()._run(query=search_query, **kwargs) From c97678bb1106ba8e7c0a9837736f89a5df5f2cd1 Mon Sep 17 00:00:00 2001 From: Naman Garg Date: Fri, 21 Jun 2024 14:48:24 -0700 Subject: [PATCH 31/62] add multion tool --- src/crewai_tools/__init__.py | 53 +++++++++--------- src/crewai_tools/tools/__init__.py | 17 ++++-- src/crewai_tools/tools/multion_tool/README.md | 31 ++++++++++ .../tools/multion_tool/example.py | 29 ++++++++++ .../tools/multion_tool/multion_tool.py | 56 +++++++++++++++++++ 5 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 src/crewai_tools/tools/multion_tool/README.md create mode 100644 src/crewai_tools/tools/multion_tool/example.py create mode 100644 src/crewai_tools/tools/multion_tool/multion_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index a51d70449..d0c4746df 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -1,27 +1,28 @@ -from .tools.base_tool import BaseTool, Tool, tool from .tools import ( - BrowserbaseLoadTool, - CodeDocsSearchTool, - CSVSearchTool, - DirectorySearchTool, - DOCXSearchTool, - DirectoryReadTool, - EXASearchTool, - FileReadTool, - GithubSearchTool, - SerperDevTool, - TXTSearchTool, - JSONSearchTool, - MDXSearchTool, - PDFSearchTool, - PGSearchTool, - RagTool, - ScrapeElementFromWebsiteTool, - ScrapeWebsiteTool, - SeleniumScrapingTool, - WebsiteSearchTool, - XMLSearchTool, - YoutubeChannelSearchTool, - YoutubeVideoSearchTool, - LlamaIndexTool -) \ No newline at end of file + BrowserbaseLoadTool, + CodeDocsSearchTool, + CSVSearchTool, + DirectoryReadTool, + DirectorySearchTool, + DOCXSearchTool, + EXASearchTool, + FileReadTool, + GithubSearchTool, + JSONSearchTool, + LlamaIndexTool, + MDXSearchTool, + MultiOnTool, + PDFSearchTool, + PGSearchTool, + RagTool, + ScrapeElementFromWebsiteTool, + ScrapeWebsiteTool, + SeleniumScrapingTool, + SerperDevTool, + TXTSearchTool, + WebsiteSearchTool, + XMLSearchTool, + YoutubeChannelSearchTool, + YoutubeVideoSearchTool, +) +from .tools.base_tool import BaseTool, Tool, tool diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 4da0c0337..11074bbe3 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -1,24 +1,29 @@ from .browserbase_load_tool.browserbase_load_tool import BrowserbaseLoadTool from .code_docs_search_tool.code_docs_search_tool import CodeDocsSearchTool from .csv_search_tool.csv_search_tool import CSVSearchTool -from .directory_search_tool.directory_search_tool import DirectorySearchTool from .directory_read_tool.directory_read_tool import DirectoryReadTool +from .directory_search_tool.directory_search_tool import DirectorySearchTool from .docx_search_tool.docx_search_tool import DOCXSearchTool from .exa_tools.exa_search_tool import EXASearchTool from .file_read_tool.file_read_tool import FileReadTool from .github_search_tool.github_search_tool import GithubSearchTool -from .serper_dev_tool.serper_dev_tool import SerperDevTool -from .txt_search_tool.txt_search_tool import TXTSearchTool from .json_search_tool.json_search_tool import JSONSearchTool +from .llamaindex_tool.llamaindex_tool import LlamaIndexTool from .mdx_seach_tool.mdx_search_tool import MDXSearchTool +from .multion_tool.multion_tool import MultiOnTool from .pdf_search_tool.pdf_search_tool import PDFSearchTool from .pg_seach_tool.pg_search_tool import PGSearchTool from .rag.rag_tool import RagTool -from .scrape_element_from_website.scrape_element_from_website import ScrapeElementFromWebsiteTool +from .scrape_element_from_website.scrape_element_from_website import ( + ScrapeElementFromWebsiteTool, +) from .scrape_website_tool.scrape_website_tool import ScrapeWebsiteTool from .selenium_scraping_tool.selenium_scraping_tool import SeleniumScrapingTool +from .serper_dev_tool.serper_dev_tool import SerperDevTool +from .txt_search_tool.txt_search_tool import TXTSearchTool from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool -from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool +from .youtube_channel_search_tool.youtube_channel_search_tool import ( + YoutubeChannelSearchTool, +) from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool -from .llamaindex_tool.llamaindex_tool import LlamaIndexTool diff --git a/src/crewai_tools/tools/multion_tool/README.md b/src/crewai_tools/tools/multion_tool/README.md new file mode 100644 index 000000000..0cbbbb2cd --- /dev/null +++ b/src/crewai_tools/tools/multion_tool/README.md @@ -0,0 +1,31 @@ +# MultiOnTool Documentation + +## Description +The MultiOnTool, integrated within the crewai_tools package, empowers CrewAI agents with the capability to navigate and interact with the web through natural language instructions. Leveraging the Multion API, this tool facilitates seamless web browsing, making it an essential asset for projects requiring dynamic web data interaction. + +## Installation +Ensure the `crewai[tools]` package is installed in your environment to use the MultiOnTool. If it's not already installed, you can add it using the command below: + +## Example +The following example demonstrates how to initialize the tool and execute a search with a given query: + +```python +from crewai_tools import MultiOnTool + +# Initialize the tool from a MultiOn Tool +multion_tool = MultiOnTool(api_key= "YOUR_MULTION_API_KEY", local=False) + +``` + +## Arguments + +- `api_key`: Specifies Browserbase API key. Defaults is the `BROWSERBASE_API_KEY` environment variable. +- `local`: Optional. Use the local flag to run the agent locally on your browser. + +## Steps to Get Started +To effectively use the `MultiOnTool`, follow these steps: + +1. **Install CrewAI**: Confirm that the `crewai[tools]` package is installed in your Python environment. +2. **Install and use MultiOn**: Follow MultiOn documentation (https://docs.multion.ai/). + + diff --git a/src/crewai_tools/tools/multion_tool/example.py b/src/crewai_tools/tools/multion_tool/example.py new file mode 100644 index 000000000..ec69e5cdf --- /dev/null +++ b/src/crewai_tools/tools/multion_tool/example.py @@ -0,0 +1,29 @@ +import os + +from crewai import Agent, Crew, Task +from multion_tool import MultiOnTool + +os.environ["OPENAI_API_KEY"] = "Your Key" + +multion_browse_tool = MultiOnTool(api_key="Your Key") + +# Create a new agent +Browser = Agent( + role="Browser Agent", + goal="control web browsers using natural language ", + backstory="An expert browsing agent.", + tools=[multion_browse_tool], + verbose=True, +) + +# Define tasks +browse = Task( + description="Summarize the top 3 trending AI News headlines", + expected_output="A summary of the top 3 trending AI News headlines", + agent=Browser, +) + + +crew = Crew(agents=[Browser], tasks=[browse]) + +crew.kickoff() diff --git a/src/crewai_tools/tools/multion_tool/multion_tool.py b/src/crewai_tools/tools/multion_tool/multion_tool.py new file mode 100644 index 000000000..1253627a2 --- /dev/null +++ b/src/crewai_tools/tools/multion_tool/multion_tool.py @@ -0,0 +1,56 @@ +"""Multion tool spec.""" + +from typing import Any, Optional + +from crewai_tools.tools.base_tool import BaseTool + + +class MultiOnTool(BaseTool): + """Tool to wrap MultiOn Browse Capabilities.""" + + name: str = "Multion Browse Tool" + description: str = """Multion gives the ability for LLMs to control web browsers using natural language instructions. + If the status is 'CONTINUE', reissue the same instruction to continue execution + """ + multion: Optional[Any] = None + session_id: Optional[str] = None + local: bool = False + + def __init__(self, api_key: Optional[str] = None, local: bool = False, **kwargs): + super().__init__(**kwargs) + try: + from multion.client import MultiOn # type: ignore + except ImportError: + raise ImportError( + "`multion` package not found, please run `pip install multion`" + ) + self.session_id = None + self.local = local + self.multion = MultiOn(api_key=api_key) + + def _run( + self, + cmd: str, + *args: Any, + **kwargs: Any, + ) -> str: + """ + Run the Multion client with the given command. + + Args: + cmd (str): The detailed and specific natural language instructrion for web browsing + + *args (Any): Additional arguments to pass to the Multion client + **kwargs (Any): Additional keyword arguments to pass to the Multion client + """ + + browse = self.multion.browse( + cmd=cmd, + session_id=self.session_id, + local=self.local, + *args, + **kwargs, + ) + self.session_id = browse.session_id + + return browse.message + "\n\n STATUS: " + browse.status From d84a61657274f925d43e7b0f9807d47589393904 Mon Sep 17 00:00:00 2001 From: Naman Garg Date: Fri, 21 Jun 2024 15:01:08 -0700 Subject: [PATCH 32/62] update local option description in readme --- src/crewai_tools/tools/multion_tool/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/multion_tool/README.md b/src/crewai_tools/tools/multion_tool/README.md index 0cbbbb2cd..608931166 100644 --- a/src/crewai_tools/tools/multion_tool/README.md +++ b/src/crewai_tools/tools/multion_tool/README.md @@ -20,7 +20,7 @@ multion_tool = MultiOnTool(api_key= "YOUR_MULTION_API_KEY", local=False) ## Arguments - `api_key`: Specifies Browserbase API key. Defaults is the `BROWSERBASE_API_KEY` environment variable. -- `local`: Optional. Use the local flag to run the agent locally on your browser. +- `local`: Optional. Use the local flag set as "true" to run the agent locally on your browser. Make sure the multion browser extension is installed and API Enabled is checked. ## Steps to Get Started To effectively use the `MultiOnTool`, follow these steps: From f9c803a8c1f13e75c526125994aa12127880b7fb Mon Sep 17 00:00:00 2001 From: Marcelo Busana Date: Sun, 23 Jun 2024 15:33:55 -0300 Subject: [PATCH 33/62] Fix: Selenium incorrect firefox options import --- .../tools/selenium_scraping_tool/selenium_scraping_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py b/src/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py index d0c420fc9..6bf8ff5f1 100644 --- a/src/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py +++ b/src/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py @@ -5,7 +5,7 @@ from pydantic.v1 import BaseModel, Field from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.by import By -from selenium.webdriver.firefox.options import Options +from selenium.webdriver.chrome.options import Options from ..base_tool import BaseTool From d4449ee5f0044e9324325bd77acc788c7d72ed1f Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Mon, 24 Jun 2024 20:48:52 +0530 Subject: [PATCH 34/62] feat: add composio CrewAI tool wrapper --- .../tools/composio_tool/README.md | 30 +++++++++ .../tools/composio_tool/composio_tool.py | 62 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/crewai_tools/tools/composio_tool/README.md create mode 100644 src/crewai_tools/tools/composio_tool/composio_tool.py diff --git a/src/crewai_tools/tools/composio_tool/README.md b/src/crewai_tools/tools/composio_tool/README.md new file mode 100644 index 000000000..ef7cf1edb --- /dev/null +++ b/src/crewai_tools/tools/composio_tool/README.md @@ -0,0 +1,30 @@ +# ComposioTool Documentation + +## Description + +This tools is a wrapper around the composio toolset and gives your agent access to a wide variety of tools from the composio SDK. + +## Installation + +To incorporate this tool into your project, follow the installation instructions below: + +```shell +pip install composio-core +pip install 'crewai[tools]' +``` + +## Example + +The following example demonstrates how to initialize the tool and execute a mathematical operation: + +```python + +from composio import Action + +from crewai_tools.tools.composio_tool.composio_tool import ComposioTool + +tool = ComposioTool.from_tool( + tool=Action.MATHEMATICAL_CALCULATOR, +) +``` + diff --git a/src/crewai_tools/tools/composio_tool/composio_tool.py b/src/crewai_tools/tools/composio_tool/composio_tool.py new file mode 100644 index 000000000..e08fbde31 --- /dev/null +++ b/src/crewai_tools/tools/composio_tool/composio_tool.py @@ -0,0 +1,62 @@ +""" +Composio tools wrapper. +""" + +import typing as t + +import typing_extensions as te + +from crewai_tools.tools.base_tool import BaseTool + + +class ComposioTool(BaseTool): + """Wrapper for composio tools.""" + + composio_action: t.Callable + + def _run(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Run the composio action with given arguments.""" + return self.composio_action(*args, **kwargs) + + @classmethod + def from_tool(cls, tool: t.Any, **kwargs: t.Any) -> te.Self: + """Wrap a composio tool as crewAI tool.""" + + from composio import Action, ComposioToolSet + from composio.constants import DEFAULT_ENTITY_ID + from composio.utils.shared import json_schema_to_model + + toolset = ComposioToolSet() + if not isinstance(tool, Action): + tool = Action.from_action(name=tool) + + tool = t.cast(Action, tool) + (action,) = toolset.get_action_schemas(actions=[tool]) + schema = action.model_dump(exclude_none=True) + entity_id = kwargs.pop("entity_id", DEFAULT_ENTITY_ID) + + def function(**kwargs: t.Any) -> t.Dict: + """Wrapper function for composio action.""" + return toolset.execute_action( + action=Action.from_app_and_action( + app=schema["appName"], + name=schema["name"], + ), + params=kwargs, + entity_id=entity_id, + ) + + function.__name__ = schema["name"] + function.__doc__ = schema["description"] + + return cls( + name=schema["name"], + description=schema["description"], + args_schema=json_schema_to_model( + action.parameters.model_dump( + exclude_none=True, + ) + ), + composio_action=function, + **kwargs + ) From f5d092f6a3a895e4c149ad15a2eb5a3756c47248 Mon Sep 17 00:00:00 2001 From: Seth Donaldson Date: Wed, 26 Jun 2024 15:46:14 -0400 Subject: [PATCH 35/62] clean copy of embedchain_adapter.py --- .../adapters/pdf_embedchain_adapter.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/crewai_tools/adapters/pdf_embedchain_adapter.py diff --git a/src/crewai_tools/adapters/pdf_embedchain_adapter.py b/src/crewai_tools/adapters/pdf_embedchain_adapter.py new file mode 100644 index 000000000..446aab96c --- /dev/null +++ b/src/crewai_tools/adapters/pdf_embedchain_adapter.py @@ -0,0 +1,25 @@ +from typing import Any + +from embedchain import App + +from crewai_tools.tools.rag.rag_tool import Adapter + + +class EmbedchainAdapter(Adapter): + embedchain_app: App + summarize: bool = False + + def query(self, question: str) -> str: + result, sources = self.embedchain_app.query( + question, citations=True, dry_run=(not self.summarize) + ) + if self.summarize: + return result + return "\n\n".join([source[0] for source in sources]) + + def add( + self, + *args: Any, + **kwargs: Any, + ) -> None: + self.embedchain_app.add(*args, **kwargs) From a95f5c27c68fa846139ae81ec9478a4b9f91c553 Mon Sep 17 00:00:00 2001 From: Seth Donaldson Date: Wed, 26 Jun 2024 15:52:54 -0400 Subject: [PATCH 36/62] Create PDFEmbedchainAdapter class and utilize it in PDFSearchTool --- .../adapters/pdf_embedchain_adapter.py | 13 ++++++++++--- .../tools/pdf_search_tool/pdf_search_tool.py | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/crewai_tools/adapters/pdf_embedchain_adapter.py b/src/crewai_tools/adapters/pdf_embedchain_adapter.py index 446aab96c..12557c971 100644 --- a/src/crewai_tools/adapters/pdf_embedchain_adapter.py +++ b/src/crewai_tools/adapters/pdf_embedchain_adapter.py @@ -1,17 +1,23 @@ -from typing import Any +from typing import Any, Optional from embedchain import App from crewai_tools.tools.rag.rag_tool import Adapter -class EmbedchainAdapter(Adapter): +class PDFEmbedchainAdapter(Adapter): embedchain_app: App summarize: bool = False + src: Optional[str] = None def query(self, question: str) -> str: + where = ( + {"app_id": self.embedchain_app.config.id, "source": self.src} + if self.src + else None + ) result, sources = self.embedchain_app.query( - question, citations=True, dry_run=(not self.summarize) + question, citations=True, dry_run=(not self.summarize), where=where ) if self.summarize: return result @@ -22,4 +28,5 @@ class EmbedchainAdapter(Adapter): *args: Any, **kwargs: Any, ) -> None: + self.src = args[0] if args else None self.embedchain_app.add(*args, **kwargs) diff --git a/src/crewai_tools/tools/pdf_search_tool/pdf_search_tool.py b/src/crewai_tools/tools/pdf_search_tool/pdf_search_tool.py index af95ae0bf..48df8e966 100644 --- a/src/crewai_tools/tools/pdf_search_tool/pdf_search_tool.py +++ b/src/crewai_tools/tools/pdf_search_tool/pdf_search_tool.py @@ -1,6 +1,7 @@ from typing import Any, Optional, Type from embedchain.models.data_type import DataType +from pydantic import model_validator from pydantic.v1 import BaseModel, Field from ..rag.rag_tool import RagTool @@ -35,6 +36,22 @@ class PDFSearchTool(RagTool): self.args_schema = FixedPDFSearchToolSchema self._generate_description() + @model_validator(mode="after") + def _set_default_adapter(self): + if isinstance(self.adapter, RagTool._AdapterPlaceholder): + from embedchain import App + + from crewai_tools.adapters.pdf_embedchain_adapter import ( + PDFEmbedchainAdapter, + ) + + app = App.from_config(config=self.config) if self.config else App() + self.adapter = PDFEmbedchainAdapter( + embedchain_app=app, summarize=self.summarize + ) + + return self + def add( self, *args: Any, From 41478abdf5665e9a912716e5b7d62a36db1e6d69 Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Thu, 27 Jun 2024 11:36:52 +0530 Subject: [PATCH 37/62] feat: define `ComposioTool` in the top level imports --- src/crewai_tools/__init__.py | 53 +++++++++++++++--------------- src/crewai_tools/tools/__init__.py | 17 ++++++---- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index a51d70449..214dbbb31 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -1,27 +1,28 @@ -from .tools.base_tool import BaseTool, Tool, tool from .tools import ( - BrowserbaseLoadTool, - CodeDocsSearchTool, - CSVSearchTool, - DirectorySearchTool, - DOCXSearchTool, - DirectoryReadTool, - EXASearchTool, - FileReadTool, - GithubSearchTool, - SerperDevTool, - TXTSearchTool, - JSONSearchTool, - MDXSearchTool, - PDFSearchTool, - PGSearchTool, - RagTool, - ScrapeElementFromWebsiteTool, - ScrapeWebsiteTool, - SeleniumScrapingTool, - WebsiteSearchTool, - XMLSearchTool, - YoutubeChannelSearchTool, - YoutubeVideoSearchTool, - LlamaIndexTool -) \ No newline at end of file + BrowserbaseLoadTool, + CodeDocsSearchTool, + ComposioTool, + CSVSearchTool, + DirectoryReadTool, + DirectorySearchTool, + DOCXSearchTool, + EXASearchTool, + FileReadTool, + GithubSearchTool, + JSONSearchTool, + LlamaIndexTool, + MDXSearchTool, + PDFSearchTool, + PGSearchTool, + RagTool, + ScrapeElementFromWebsiteTool, + ScrapeWebsiteTool, + SeleniumScrapingTool, + SerperDevTool, + TXTSearchTool, + WebsiteSearchTool, + XMLSearchTool, + YoutubeChannelSearchTool, + YoutubeVideoSearchTool, +) +from .tools.base_tool import BaseTool, Tool, tool diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 4da0c0337..df0ec7286 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -1,24 +1,29 @@ from .browserbase_load_tool.browserbase_load_tool import BrowserbaseLoadTool from .code_docs_search_tool.code_docs_search_tool import CodeDocsSearchTool +from .composio_tool.composio_tool import ComposioTool from .csv_search_tool.csv_search_tool import CSVSearchTool -from .directory_search_tool.directory_search_tool import DirectorySearchTool from .directory_read_tool.directory_read_tool import DirectoryReadTool +from .directory_search_tool.directory_search_tool import DirectorySearchTool from .docx_search_tool.docx_search_tool import DOCXSearchTool from .exa_tools.exa_search_tool import EXASearchTool from .file_read_tool.file_read_tool import FileReadTool from .github_search_tool.github_search_tool import GithubSearchTool -from .serper_dev_tool.serper_dev_tool import SerperDevTool -from .txt_search_tool.txt_search_tool import TXTSearchTool from .json_search_tool.json_search_tool import JSONSearchTool +from .llamaindex_tool.llamaindex_tool import LlamaIndexTool from .mdx_seach_tool.mdx_search_tool import MDXSearchTool from .pdf_search_tool.pdf_search_tool import PDFSearchTool from .pg_seach_tool.pg_search_tool import PGSearchTool from .rag.rag_tool import RagTool -from .scrape_element_from_website.scrape_element_from_website import ScrapeElementFromWebsiteTool +from .scrape_element_from_website.scrape_element_from_website import ( + ScrapeElementFromWebsiteTool, +) from .scrape_website_tool.scrape_website_tool import ScrapeWebsiteTool from .selenium_scraping_tool.selenium_scraping_tool import SeleniumScrapingTool +from .serper_dev_tool.serper_dev_tool import SerperDevTool +from .txt_search_tool.txt_search_tool import TXTSearchTool from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool -from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool +from .youtube_channel_search_tool.youtube_channel_search_tool import ( + YoutubeChannelSearchTool, +) from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool -from .llamaindex_tool.llamaindex_tool import LlamaIndexTool From be6e1a79dd136ed8b3e36947203e1e7b91f95eee Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Thu, 27 Jun 2024 11:39:42 +0530 Subject: [PATCH 38/62] feat: add search utility methods --- .../tools/composio_tool/composio_tool.py | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/crewai_tools/tools/composio_tool/composio_tool.py b/src/crewai_tools/tools/composio_tool/composio_tool.py index e08fbde31..664898ce3 100644 --- a/src/crewai_tools/tools/composio_tool/composio_tool.py +++ b/src/crewai_tools/tools/composio_tool/composio_tool.py @@ -19,7 +19,11 @@ class ComposioTool(BaseTool): return self.composio_action(*args, **kwargs) @classmethod - def from_tool(cls, tool: t.Any, **kwargs: t.Any) -> te.Self: + def from_tool( + cls, + tool: t.Any, + **kwargs: t.Any, + ) -> te.Self: """Wrap a composio tool as crewAI tool.""" from composio import Action, ComposioToolSet @@ -28,7 +32,7 @@ class ComposioTool(BaseTool): toolset = ComposioToolSet() if not isinstance(tool, Action): - tool = Action.from_action(name=tool) + tool = Action(tool) tool = t.cast(Action, tool) (action,) = toolset.get_action_schemas(actions=[tool]) @@ -38,10 +42,7 @@ class ComposioTool(BaseTool): def function(**kwargs: t.Any) -> t.Dict: """Wrapper function for composio action.""" return toolset.execute_action( - action=Action.from_app_and_action( - app=schema["appName"], - name=schema["name"], - ), + action=Action(schema["name"]), params=kwargs, entity_id=entity_id, ) @@ -58,5 +59,42 @@ class ComposioTool(BaseTool): ) ), composio_action=function, - **kwargs + **kwargs, ) + + @classmethod + def from_app( + cls, + app: t.Any, + tags: t.Optional[t.List[str]] = None, + **kwargs: t.Any, + ) -> t.List[te.Self]: + """Create toolset from an app.""" + from composio import App + + if not isinstance(app, App): + app = App(app) + + return [ + cls.from_tool(tool=action, **kwargs) + for action in app.get_actions(tags=tags) + ] + + @classmethod + def from_use_case( + cls, + *apps: t.Any, + use_case: str, + **kwargs: t.Any, + ) -> t.List[te.Self]: + """Create toolset from an app.""" + if len(apps) == 0: + raise ValueError( + "You need to provide at least one app name to search by use case" + ) + + from composio import ComposioToolSet + + toolset = ComposioToolSet() + actions = toolset.find_actions_by_use_case(*apps, use_case=use_case) + return [cls.from_tool(tool=action, **kwargs) for action in actions] From ab484172ef2d3237fb14416ca2894db3568e216b Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Thu, 27 Jun 2024 11:40:02 +0530 Subject: [PATCH 39/62] chore: update readme --- .../tools/composio_tool/README.md | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/crewai_tools/tools/composio_tool/README.md b/src/crewai_tools/tools/composio_tool/README.md index ef7cf1edb..4a4db85d5 100644 --- a/src/crewai_tools/tools/composio_tool/README.md +++ b/src/crewai_tools/tools/composio_tool/README.md @@ -15,16 +15,55 @@ pip install 'crewai[tools]' ## Example -The following example demonstrates how to initialize the tool and execute a mathematical operation: +The following example demonstrates how to initialize the tool and execute a github action: + +1. Initialize toolset ```python +from composio import App +from crewai_tools import ComposioTool +from crewai import Agent, Task -from composio import Action -from crewai_tools.tools.composio_tool.composio_tool import ComposioTool +tools = [ComposioTool.from_tool(tool=Action.GITHUB_ACTIVITY_STAR_REPO_FOR_AUTHENTICATED_USER)] +``` -tool = ComposioTool.from_tool( - tool=Action.MATHEMATICAL_CALCULATOR, +If you don't know what action you want to use, use `from_app` and `tags` filter to get relevant actions + +```python +tools = ComposioTool.from_app(app=App.GITHUB, tags=["important"]) +``` + +or use `from_use_case` to search relevant actions + +```python +tools = ComposioTool.from_use_case(App.GITHUB, use_case="Star a github repository") +``` + +2. Define agent + +```python +crewai_agent = Agent( + role="Github Agent", + goal="""You take action on Github using Github APIs""", + backstory=( + "You are AI agent that is responsible for taking actions on Github " + "on users behalf. You need to take action on Github using Github APIs" + ), + verbose=True, + tools=tools, ) ``` +3. Execute task + +```python +task = Task( + description="Star a repo ComposioHQ/composio on GitHub", + agent=crewai_agent, + expected_output="if the star happened", +) + +task.execute() +``` + From 369c03a257c6c11c5620d3bcf4e66310a649c193 Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Thu, 27 Jun 2024 12:16:22 +0530 Subject: [PATCH 40/62] feat: add check for auth accounts --- .../tools/composio_tool/composio_tool.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/crewai_tools/tools/composio_tool/composio_tool.py b/src/crewai_tools/tools/composio_tool/composio_tool.py index 664898ce3..fd478eeb6 100644 --- a/src/crewai_tools/tools/composio_tool/composio_tool.py +++ b/src/crewai_tools/tools/composio_tool/composio_tool.py @@ -18,6 +18,26 @@ class ComposioTool(BaseTool): """Run the composio action with given arguments.""" return self.composio_action(*args, **kwargs) + @staticmethod + def _check_connected_account(tool: t.Any, toolset: t.Any) -> None: + """Check if connected account is required and if required it exists or not.""" + from composio import Action + from composio.client.collections import ConnectedAccountModel + + tool = t.cast(Action, tool) + if tool.no_auth: + return + + connections = t.cast( + t.List[ConnectedAccountModel], + toolset.client.connected_accounts.get(), + ) + if tool.app not in [connection.appUniqueId for connection in connections]: + raise RuntimeError( + f"No connected account found for app `{tool.app}`; " + f"Run `composio add {tool.app}` to fix this" + ) + @classmethod def from_tool( cls, @@ -35,6 +55,11 @@ class ComposioTool(BaseTool): tool = Action(tool) tool = t.cast(Action, tool) + cls._check_connected_account( + tool=tool, + toolset=toolset, + ) + (action,) = toolset.get_action_schemas(actions=[tool]) schema = action.model_dump(exclude_none=True) entity_id = kwargs.pop("entity_id", DEFAULT_ENTITY_ID) From 58354ec638326a4b406aa97d6038d2fc7d6df418 Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Thu, 27 Jun 2024 12:23:05 +0530 Subject: [PATCH 41/62] chore: update README --- src/crewai_tools/tools/composio_tool/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/composio_tool/README.md b/src/crewai_tools/tools/composio_tool/README.md index 4a4db85d5..fe030cbd2 100644 --- a/src/crewai_tools/tools/composio_tool/README.md +++ b/src/crewai_tools/tools/composio_tool/README.md @@ -13,6 +13,8 @@ pip install composio-core pip install 'crewai[tools]' ``` +after the installation is complete, either run `composio login` or export your composio API key as `COMPOSIO_API_KEY`. + ## Example The following example demonstrates how to initialize the tool and execute a github action: @@ -45,7 +47,7 @@ tools = ComposioTool.from_use_case(App.GITHUB, use_case="Star a github repositor ```python crewai_agent = Agent( role="Github Agent", - goal="""You take action on Github using Github APIs""", + goal="You take action on Github using Github APIs", backstory=( "You are AI agent that is responsible for taking actions on Github " "on users behalf. You need to take action on Github using Github APIs" @@ -67,3 +69,4 @@ task = Task( task.execute() ``` +* More detailed list of tools can be found [here](https://app.composio.dev) From 9a8d88b8aa3890897d75814fd4b916d3dba706b7 Mon Sep 17 00:00:00 2001 From: angrybayblade Date: Thu, 27 Jun 2024 13:35:57 +0530 Subject: [PATCH 42/62] fix: merge `from_app` and `from_use_case` --- .../tools/composio_tool/README.md | 8 +-- .../tools/composio_tool/composio_tool.py | 59 +++++++++---------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/crewai_tools/tools/composio_tool/README.md b/src/crewai_tools/tools/composio_tool/README.md index fe030cbd2..18045e7f1 100644 --- a/src/crewai_tools/tools/composio_tool/README.md +++ b/src/crewai_tools/tools/composio_tool/README.md @@ -27,19 +27,19 @@ from crewai_tools import ComposioTool from crewai import Agent, Task -tools = [ComposioTool.from_tool(tool=Action.GITHUB_ACTIVITY_STAR_REPO_FOR_AUTHENTICATED_USER)] +tools = [ComposioTool.from_action(action=Action.GITHUB_ACTIVITY_STAR_REPO_FOR_AUTHENTICATED_USER)] ``` If you don't know what action you want to use, use `from_app` and `tags` filter to get relevant actions ```python -tools = ComposioTool.from_app(app=App.GITHUB, tags=["important"]) +tools = ComposioTool.from_app(App.GITHUB, tags=["important"]) ``` -or use `from_use_case` to search relevant actions +or use `use_case` to search relevant actions ```python -tools = ComposioTool.from_use_case(App.GITHUB, use_case="Star a github repository") +tools = ComposioTool.from_app(App.GITHUB, use_case="Star a github repository") ``` 2. Define agent diff --git a/src/crewai_tools/tools/composio_tool/composio_tool.py b/src/crewai_tools/tools/composio_tool/composio_tool.py index fd478eeb6..62068c0bd 100644 --- a/src/crewai_tools/tools/composio_tool/composio_tool.py +++ b/src/crewai_tools/tools/composio_tool/composio_tool.py @@ -39,9 +39,9 @@ class ComposioTool(BaseTool): ) @classmethod - def from_tool( + def from_action( cls, - tool: t.Any, + action: t.Any, **kwargs: t.Any, ) -> te.Self: """Wrap a composio tool as crewAI tool.""" @@ -51,17 +51,17 @@ class ComposioTool(BaseTool): from composio.utils.shared import json_schema_to_model toolset = ComposioToolSet() - if not isinstance(tool, Action): - tool = Action(tool) + if not isinstance(action, Action): + action = Action(action) - tool = t.cast(Action, tool) + action = t.cast(Action, action) cls._check_connected_account( - tool=tool, + tool=action, toolset=toolset, ) - (action,) = toolset.get_action_schemas(actions=[tool]) - schema = action.model_dump(exclude_none=True) + (action_schema,) = toolset.get_action_schemas(actions=[action]) + schema = action_schema.model_dump(exclude_none=True) entity_id = kwargs.pop("entity_id", DEFAULT_ENTITY_ID) def function(**kwargs: t.Any) -> t.Dict: @@ -79,7 +79,7 @@ class ComposioTool(BaseTool): name=schema["name"], description=schema["description"], args_schema=json_schema_to_model( - action.parameters.model_dump( + action_schema.parameters.model_dump( exclude_none=True, ) ), @@ -89,37 +89,34 @@ class ComposioTool(BaseTool): @classmethod def from_app( - cls, - app: t.Any, - tags: t.Optional[t.List[str]] = None, - **kwargs: t.Any, - ) -> t.List[te.Self]: - """Create toolset from an app.""" - from composio import App - - if not isinstance(app, App): - app = App(app) - - return [ - cls.from_tool(tool=action, **kwargs) - for action in app.get_actions(tags=tags) - ] - - @classmethod - def from_use_case( cls, *apps: t.Any, - use_case: str, + tags: t.Optional[t.List[str]] = None, + use_case: t.Optional[str] = None, **kwargs: t.Any, ) -> t.List[te.Self]: """Create toolset from an app.""" if len(apps) == 0: + raise ValueError("You need to provide at least one app name") + + if use_case is None and tags is None: + raise ValueError("Both `use_case` and `tags` cannot be `None`") + + if use_case is not None and tags is not None: raise ValueError( - "You need to provide at least one app name to search by use case" + "Cannot use both `use_case` and `tags` to filter the actions" ) from composio import ComposioToolSet toolset = ComposioToolSet() - actions = toolset.find_actions_by_use_case(*apps, use_case=use_case) - return [cls.from_tool(tool=action, **kwargs) for action in actions] + if use_case is not None: + return [ + cls.from_action(action=action, **kwargs) + for action in toolset.find_actions_by_use_case(*apps, use_case=use_case) + ] + + return [ + cls.from_action(action=action, **kwargs) + for action in toolset.find_actions_by_tags(*apps, tags=tags) + ] From a3d3a70b5a4f87b27089759938cee08a6a9d3f31 Mon Sep 17 00:00:00 2001 From: Mervin Praison Date: Mon, 1 Jul 2024 04:34:39 +0100 Subject: [PATCH 43/62] Update __init__.py to Add CodeInterpreterTool --- src/crewai_tools/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index a51d70449..1398dcfaf 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -2,6 +2,7 @@ from .tools.base_tool import BaseTool, Tool, tool from .tools import ( BrowserbaseLoadTool, CodeDocsSearchTool, + CodeInterpreterTool, CSVSearchTool, DirectorySearchTool, DOCXSearchTool, @@ -24,4 +25,4 @@ from .tools import ( YoutubeChannelSearchTool, YoutubeVideoSearchTool, LlamaIndexTool -) \ No newline at end of file +) From f79c385bf76a1dcd0595cfc7bd111fa1928a87d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Mon, 1 Jul 2024 00:55:21 -0700 Subject: [PATCH 44/62] revamping code interpreter --- .../code_interpreter_tool.py | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py index 06cb081f0..ec756d8c0 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py +++ b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py @@ -1,69 +1,62 @@ import os -from typing import Optional, Type +import importlib.util +import textwrap +from typing import List, Optional, Type import docker from crewai_tools.tools.base_tool import BaseTool from pydantic.v1 import BaseModel, Field -class FixedCodeInterpreterSchemaSchema(BaseModel): +class CodeInterpreterSchema(BaseModel): """Input for CodeInterpreterTool.""" - - pass - - -class CodeInterpreterSchema(FixedCodeInterpreterSchemaSchema): - """Input for CodeInterpreterTool.""" - code: str = Field( ..., - description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code", + description="Mandatory string of python3 code used to be interpreted with a final print statement.", ) - libraries_used: Optional[str] = Field( - None, - description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4", + dependencies_used_in_code: List[str] = Field( + ..., + description="Mandatory list of libraries used in the code with proper installing names.", ) - class CodeInterpreterTool(BaseTool): name: str = "Code Interpreter" - description: str = "Interprets Python code in a Docker container. ALWAYS PRINT the final result and the output of the code" + description: str = "Interprets Python3 code strings with a final print statement." args_schema: Type[BaseModel] = CodeInterpreterSchema code: Optional[str] = None + @staticmethod + def _get_installed_package_path(): + spec = importlib.util.find_spec('crewai_tools') + return os.path.dirname(spec.origin) + def _verify_docker_image(self) -> None: """ Verify if the Docker image is available """ image_tag = "code-interpreter:latest" - client = docker.from_env() - images = client.images.list() - all_tags = [tag for image in images for tag in image.tags] + try: + client.images.get(image_tag) + except: + package_path = self._get_installed_package_path() + dockerfile_path = os.path.join(package_path, 'tools/code_interpreter_tool') + if not os.path.exists(dockerfile_path): + raise FileNotFoundError(f"Dockerfile not found in {dockerfile_path}") - if image_tag not in all_tags: client.images.build( - path=os.path.dirname(os.path.abspath(__file__)), + path=dockerfile_path, tag=image_tag, rm=True, ) - def __init__(self, code: Optional[str] = None, **kwargs) -> None: - super().__init__(**kwargs) - if code is not None: - self._verify_docker_image() - self.code = code - self.description = "Interprets Python code in a Docker container. ALWAYS PRINT the final result and the output of the code" - self.args_schema = FixedCodeInterpreterSchemaSchema - self._generate_description() - def _run(self, **kwargs) -> str: code = kwargs.get("code", self.code) - libraries_used = kwargs.get("libraries_used", None) + libraries_used = kwargs.get("dependencies_used_in_code", []) return self.run_code_in_docker(code, libraries_used) def _install_libraries( - self, container: docker.models.containers.Container, libraries: list[str] + self, container: docker.models.containers.Container, libraries: List[str] ) -> None: """ Install missing libraries in the Docker container @@ -78,10 +71,9 @@ class CodeInterpreterTool(BaseTool): ) def run_code_in_docker(self, code: str, libraries_used: str) -> str: + self._verify_docker_image() container = self._init_docker_container() - - if libraries_used: - self._install_libraries(container, libraries_used.split(",")) + self._install_libraries(container, libraries_used) cmd_to_run = f'python3 -c "{code}"' exec_result = container.exec_run(cmd_to_run) From d000bd2fc8eaed205b77064bc4f908ba6c8aed4e Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Tue, 2 Jul 2024 12:00:04 -0300 Subject: [PATCH 45/62] fix: add code interpreter tool --- src/crewai_tools/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index 1cc222ec9..b85a16ffb 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -1,6 +1,7 @@ from .tools import ( BrowserbaseLoadTool, CodeDocsSearchTool, + CodeInterpreterTool, ComposioTool, CSVSearchTool, DirectoryReadTool, @@ -25,4 +26,4 @@ from .tools import ( YoutubeChannelSearchTool, YoutubeVideoSearchTool, ) -from .tools.base_tool import BaseTool, Tool, tool \ No newline at end of file +from .tools.base_tool import BaseTool, Tool, tool From b4d91d1ce01644893eb0c93be84d5067616f5f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Thu, 4 Jul 2024 00:09:18 -0400 Subject: [PATCH 46/62] adding new result_as_answer options --- src/crewai_tools/tools/base_tool.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crewai_tools/tools/base_tool.py b/src/crewai_tools/tools/base_tool.py index e8e497859..4e0bd1fd5 100644 --- a/src/crewai_tools/tools/base_tool.py +++ b/src/crewai_tools/tools/base_tool.py @@ -22,6 +22,8 @@ class BaseTool(BaseModel, ABC): """Flag to check if the description has been updated.""" cache_function: Optional[Callable] = lambda _args, _result: True """Function that will be used to determine if the tool should be cached, should return a boolean. If None, the tool will be cached.""" + result_as_answer: bool = False + """Flag to check if the tool should be the final agent answer.""" @validator("args_schema", always=True, pre=True) def _default_args_schema(cls, v: Type[V1BaseModel]) -> Type[V1BaseModel]: From ba05d18ab16db4dd36f3b3ce414d3652ccfc9d20 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 4 Jul 2024 16:42:29 -0300 Subject: [PATCH 47/62] fix: fix type hinting, add container name and handle exception and returned old description --- .../code_interpreter_tool.py | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py index ec756d8c0..f341e52d0 100644 --- a/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py +++ b/src/crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py @@ -1,6 +1,5 @@ -import os import importlib.util -import textwrap +import os from typing import List, Optional, Type import docker @@ -10,15 +9,18 @@ from pydantic.v1 import BaseModel, Field class CodeInterpreterSchema(BaseModel): """Input for CodeInterpreterTool.""" + code: str = Field( ..., - description="Mandatory string of python3 code used to be interpreted with a final print statement.", + description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code", ) - dependencies_used_in_code: List[str] = Field( + + libraries_used: List[str] = Field( ..., - description="Mandatory list of libraries used in the code with proper installing names.", + description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4", ) + class CodeInterpreterTool(BaseTool): name: str = "Code Interpreter" description: str = "Interprets Python3 code strings with a final print statement." @@ -27,7 +29,7 @@ class CodeInterpreterTool(BaseTool): @staticmethod def _get_installed_package_path(): - spec = importlib.util.find_spec('crewai_tools') + spec = importlib.util.find_spec("crewai_tools") return os.path.dirname(spec.origin) def _verify_docker_image(self) -> None: @@ -36,11 +38,13 @@ class CodeInterpreterTool(BaseTool): """ image_tag = "code-interpreter:latest" client = docker.from_env() + try: client.images.get(image_tag) - except: + + except docker.errors.ImageNotFound: package_path = self._get_installed_package_path() - dockerfile_path = os.path.join(package_path, 'tools/code_interpreter_tool') + dockerfile_path = os.path.join(package_path, "tools/code_interpreter_tool") if not os.path.exists(dockerfile_path): raise FileNotFoundError(f"Dockerfile not found in {dockerfile_path}") @@ -52,7 +56,7 @@ class CodeInterpreterTool(BaseTool): def _run(self, **kwargs) -> str: code = kwargs.get("code", self.code) - libraries_used = kwargs.get("dependencies_used_in_code", []) + libraries_used = kwargs.get("libraries_used", []) return self.run_code_in_docker(code, libraries_used) def _install_libraries( @@ -67,10 +71,14 @@ class CodeInterpreterTool(BaseTool): def _init_docker_container(self) -> docker.models.containers.Container: client = docker.from_env() return client.containers.run( - "code-interpreter", detach=True, tty=True, working_dir="/workspace" + "code-interpreter", + detach=True, + tty=True, + working_dir="/workspace", + name="code-interpreter", ) - def run_code_in_docker(self, code: str, libraries_used: str) -> str: + def run_code_in_docker(self, code: str, libraries_used: List[str]) -> str: self._verify_docker_image() container = self._init_docker_container() self._install_libraries(container, libraries_used) From a5d283943160e10185aa6bc6353d7c79d1c64aa9 Mon Sep 17 00:00:00 2001 From: Jakub Strnad Date: Fri, 5 Jul 2024 16:30:41 +0200 Subject: [PATCH 48/62] arguments descriptions added to tool description so now the agent knows how to use the tools params --- src/crewai_tools/tools/base_tool.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/crewai_tools/tools/base_tool.py b/src/crewai_tools/tools/base_tool.py index 4e0bd1fd5..dff1e37aa 100644 --- a/src/crewai_tools/tools/base_tool.py +++ b/src/crewai_tools/tools/base_tool.py @@ -86,13 +86,16 @@ class BaseTool(BaseModel, ABC): ) def _generate_description(self): - args = [] - for arg, attribute in self.args_schema.schema()["properties"].items(): - if "type" in attribute: - args.append(f"{arg}: '{attribute['type']}'") + args = [] + args_description = [] + for arg, attribute in self.args_schema.schema()["properties"].items(): + if "type" in attribute: + args.append(f"{arg}: '{attribute['type']}'") + if "description" in attribute: + args_description.append(f"{arg}: '{attribute['description']}'") - description = self.description.replace("\n", " ") - self.description = f"{self.name}({', '.join(args)}) - {description}" + description = self.description.replace("\n", " ") + self.description = f"{self.name}({', '.join(args)}) - {description} {', '.join(args_description)}" class Tool(BaseTool): From cb1dc13a9d214622f8ea8d0c3573b4207c9402bf Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 5 Jul 2024 18:42:16 +0200 Subject: [PATCH 49/62] fixed intendation --- src/crewai_tools/tools/base_tool.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/crewai_tools/tools/base_tool.py b/src/crewai_tools/tools/base_tool.py index dff1e37aa..4b60d93d4 100644 --- a/src/crewai_tools/tools/base_tool.py +++ b/src/crewai_tools/tools/base_tool.py @@ -86,16 +86,16 @@ class BaseTool(BaseModel, ABC): ) def _generate_description(self): - args = [] - args_description = [] - for arg, attribute in self.args_schema.schema()["properties"].items(): - if "type" in attribute: - args.append(f"{arg}: '{attribute['type']}'") - if "description" in attribute: - args_description.append(f"{arg}: '{attribute['description']}'") + args = [] + args_description = [] + for arg, attribute in self.args_schema.schema()["properties"].items(): + if "type" in attribute: + args.append(f"{arg}: '{attribute['type']}'") + if "description" in attribute: + args_description.append(f"{arg}: '{attribute['description']}'") - description = self.description.replace("\n", " ") - self.description = f"{self.name}({', '.join(args)}) - {description} {', '.join(args_description)}" + description = self.description.replace("\n", " ") + self.description = f"{self.name}({', '.join(args)}) - {description} {', '.join(args_description)}" class Tool(BaseTool): From f056764132b5caa93846ad67fbc1fce841255796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Mon, 8 Jul 2024 01:15:00 -0400 Subject: [PATCH 50/62] adding firecrawl imports --- src/crewai_tools/__init__.py | 3 +++ src/crewai_tools/tools/__init__.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index b85a16ffb..a9c9a4168 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -9,6 +9,9 @@ from .tools import ( DOCXSearchTool, EXASearchTool, FileReadTool, + FirecrawlCrawlWebsiteTool, + FirecrawlScrapeWebsiteTool, + FirecrawlSearchTool, GithubSearchTool, JSONSearchTool, LlamaIndexTool, diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index f5ac94052..17d289832 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -8,6 +8,9 @@ from .directory_search_tool.directory_search_tool import DirectorySearchTool from .docx_search_tool.docx_search_tool import DOCXSearchTool from .exa_tools.exa_search_tool import EXASearchTool from .file_read_tool.file_read_tool import FileReadTool +from .firecrawl_crawl_website_tool.firecrawl_crawl_website_tool import FirecrawlCrawlWebsiteTool +from .firecrawl_scrape_website_tool.firecrawl_scrape_website_tool import FirecrawlScrapeWebsiteTool +from .firecrawl_search_tool.firecrawl_search_tool import FirecrawlSearchTool from .github_search_tool.github_search_tool import GithubSearchTool from .json_search_tool.json_search_tool import JSONSearchTool from .llamaindex_tool.llamaindex_tool import LlamaIndexTool From 65855cbe56e243bc61b8b48e3f731b5c5c1c3627 Mon Sep 17 00:00:00 2001 From: Jakub Strnad Date: Mon, 8 Jul 2024 15:24:26 +0200 Subject: [PATCH 51/62] bugfix: ScrapeWebsiteTool encoding fixed problem with garbage output of ScrapeWebsiteTool on some websites --- .../tools/scrape_website_tool/scrape_website_tool.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py b/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py index 148a0b320..e59064151 100644 --- a/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py +++ b/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py @@ -25,8 +25,7 @@ class ScrapeWebsiteTool(BaseTool): 'Accept-Language': 'en-US,en;q=0.9', 'Referer': 'https://www.google.com/', 'Connection': 'keep-alive', - 'Upgrade-Insecure-Requests': '1', - 'Accept-Encoding': 'gzip, deflate, br' + 'Upgrade-Insecure-Requests': '1' } def __init__(self, website_url: Optional[str] = None, cookies: Optional[dict] = None, **kwargs): From 6f45c6ed0949fece97b48ecf29df22336ec365e8 Mon Sep 17 00:00:00 2001 From: Naman Garg Date: Mon, 8 Jul 2024 15:11:04 -0700 Subject: [PATCH 52/62] Updated Readme --- src/crewai_tools/tools/multion_tool/README.md | 29 +++++++++++++++++-- .../tools/multion_tool/multion_tool.py | 11 ++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/crewai_tools/tools/multion_tool/README.md b/src/crewai_tools/tools/multion_tool/README.md index 608931166..ea530037f 100644 --- a/src/crewai_tools/tools/multion_tool/README.md +++ b/src/crewai_tools/tools/multion_tool/README.md @@ -5,27 +5,50 @@ The MultiOnTool, integrated within the crewai_tools package, empowers CrewAI age ## Installation Ensure the `crewai[tools]` package is installed in your environment to use the MultiOnTool. If it's not already installed, you can add it using the command below: +```shell +pip install 'crewai[tools]' +``` ## Example The following example demonstrates how to initialize the tool and execute a search with a given query: ```python +from crewai import Agent, Task, Crew from crewai_tools import MultiOnTool # Initialize the tool from a MultiOn Tool multion_tool = MultiOnTool(api_key= "YOUR_MULTION_API_KEY", local=False) +Browser = Agent( + role="Browser Agent", + goal="control web browsers using natural language ", + backstory="An expert browsing agent.", + tools=[multion_remote_tool], + verbose=True, +) + +# example task to search and summarize news +browse = Task( + description="Summarize the top 3 trending AI News headlines", + expected_output="A summary of the top 3 trending AI News headlines", + agent=Browser, +) + +crew = Crew(agents=[Browser], tasks=[browse]) + +crew.kickoff() ``` ## Arguments - `api_key`: Specifies Browserbase API key. Defaults is the `BROWSERBASE_API_KEY` environment variable. -- `local`: Optional. Use the local flag set as "true" to run the agent locally on your browser. Make sure the multion browser extension is installed and API Enabled is checked. +- `local`: Use the local flag set as "true" to run the agent locally on your browser. Make sure the multion browser extension is installed and API Enabled is checked. +- `max_steps`: Optional. Set the max_steps the multion agent can take for a command ## Steps to Get Started To effectively use the `MultiOnTool`, follow these steps: 1. **Install CrewAI**: Confirm that the `crewai[tools]` package is installed in your Python environment. -2. **Install and use MultiOn**: Follow MultiOn documentation (https://docs.multion.ai/). - +2. **Install and use MultiOn**: Follow MultiOn documentation for installing the MultiOn Browser Extension (https://docs.multion.ai/learn/browser-extension). +3. **Enable API Usage**: Click on the MultiOn extension in the extensions folder of your browser (not the hovering MultiOn icon on the web page) to open the extension configurations. Click the API Enabled toggle to enable the API diff --git a/src/crewai_tools/tools/multion_tool/multion_tool.py b/src/crewai_tools/tools/multion_tool/multion_tool.py index 1253627a2..2dc944f23 100644 --- a/src/crewai_tools/tools/multion_tool/multion_tool.py +++ b/src/crewai_tools/tools/multion_tool/multion_tool.py @@ -15,8 +15,15 @@ class MultiOnTool(BaseTool): multion: Optional[Any] = None session_id: Optional[str] = None local: bool = False + max_steps: int = 3 - def __init__(self, api_key: Optional[str] = None, local: bool = False, **kwargs): + def __init__( + self, + api_key: Optional[str] = None, + local: bool = False, + max_steps: int = 3, + **kwargs, + ): super().__init__(**kwargs) try: from multion.client import MultiOn # type: ignore @@ -27,6 +34,7 @@ class MultiOnTool(BaseTool): self.session_id = None self.local = local self.multion = MultiOn(api_key=api_key) + self.max_steps = max_steps def _run( self, @@ -48,6 +56,7 @@ class MultiOnTool(BaseTool): cmd=cmd, session_id=self.session_id, local=self.local, + max_steps=self.max_steps, *args, **kwargs, ) From f447f71a8ee017298acaac590e30b9ca5ae2589e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Sun, 14 Jul 2024 17:59:17 -0300 Subject: [PATCH 53/62] Update serper_dev_tool.py --- .../tools/serper_dev_tool/serper_dev_tool.py | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py index 77d008be9..651d9c5a6 100644 --- a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py +++ b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py @@ -27,7 +27,7 @@ class SerperDevTool(BaseTool): location: Optional[str] = None locale: Optional[str] = None n_results: int = Field(default=10, description="Number of search results to return") - save_file: bool = Field(default=False, description="Flag to determine whether to save the results to a file") + save_file: bool = Field(default=False, description="Flag to determine whether to save the results to a file") def _run( self, @@ -35,22 +35,19 @@ class SerperDevTool(BaseTool): ) -> Any: search_query = kwargs.get('search_query') or kwargs.get('query') - save_file = kwargs.get('save_file', self.save_file) - n_results = kwargs.get('n_results', self.n_results) + save_file = kwargs.get('save_file', self.save_file) + n_results = kwargs.get('n_results', self.n_results) - payload = json.dumps( - { - "q": search_query, - "num": n_results, - "gl": self.country, - "location": self.location, - "hl": self.locale, - } - ) + payload = { "q": search_query, "num": n_results } + payload["gl"] = self.country if self.country + payload["location"] = self.country if self.location + payload["hl"] = self.country if self.locale + + payload = json.dumps(payload) headers = { 'X-API-KEY': os.environ['SERPER_API_KEY'], - 'content-type': 'application/json' + 'content-type': 'application/json' } response = requests.request("POST", self.search_url, headers=headers, data=payload) results = response.json() From 0386120a5ac86368c72293b243d653ef5b941645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Fri, 19 Jul 2024 00:28:27 -0400 Subject: [PATCH 54/62] fixing serper tool --- .../scrape_website_tool.py | 10 +++-- .../tools/serper_dev_tool/serper_dev_tool.py | 37 +++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py b/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py index e59064151..92f84cba9 100644 --- a/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py +++ b/src/crewai_tools/tools/scrape_website_tool/scrape_website_tool.py @@ -39,8 +39,8 @@ class ScrapeWebsiteTool(BaseTool): self.cookies = {cookies["name"]: os.getenv(cookies["value"])} def _run( - self, - **kwargs: Any, + self, + **kwargs: Any, ) -> Any: website_url = kwargs.get('website_url', self.website_url) page = requests.get( @@ -49,9 +49,11 @@ class ScrapeWebsiteTool(BaseTool): headers=self.headers, cookies=self.cookies if self.cookies else {} ) - parsed = BeautifulSoup(page.content, "html.parser") + + page.encoding = page.apparent_encoding + parsed = BeautifulSoup(page.text, "html.parser") + text = parsed.get_text() text = '\n'.join([i for i in text.split('\n') if i.strip() != '']) text = ' '.join([i for i in text.split(' ') if i.strip() != '']) return text - diff --git a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py index 651d9c5a6..f89768064 100644 --- a/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py +++ b/src/crewai_tools/tools/serper_dev_tool/serper_dev_tool.py @@ -1,3 +1,4 @@ +import datetime import os import json import requests @@ -7,11 +8,11 @@ from pydantic.v1 import BaseModel, Field from crewai_tools.tools.base_tool import BaseTool def _save_results_to_file(content: str) -> None: - """Saves the search results to a file.""" - filename = f"search_results_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt" - with open(filename, 'w') as file: - file.write(content) - print(f"Results saved to {filename}") + """Saves the search results to a file.""" + filename = f"search_results_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt" + with open(filename, 'w') as file: + file.write(content) + print(f"Results saved to {filename}") class SerperDevToolSchema(BaseModel): @@ -23,11 +24,11 @@ class SerperDevTool(BaseTool): description: str = "A tool that can be used to search the internet with a search_query." args_schema: Type[BaseModel] = SerperDevToolSchema search_url: str = "https://google.serper.dev/search" - country: Optional[str] = None - location: Optional[str] = None - locale: Optional[str] = None - n_results: int = Field(default=10, description="Number of search results to return") - save_file: bool = Field(default=False, description="Flag to determine whether to save the results to a file") + country: Optional[str] = '' + location: Optional[str] = '' + locale: Optional[str] = '' + n_results: int = 10 + save_file: bool = False def _run( self, @@ -39,18 +40,24 @@ class SerperDevTool(BaseTool): n_results = kwargs.get('n_results', self.n_results) payload = { "q": search_query, "num": n_results } - payload["gl"] = self.country if self.country - payload["location"] = self.country if self.location - payload["hl"] = self.country if self.locale - + + if self.country != '': + payload["gl"] = self.country + if self.location != '': + payload["location"] = self.location + if self.locale != '': + payload["hl"] = self.locale + payload = json.dumps(payload) headers = { 'X-API-KEY': os.environ['SERPER_API_KEY'], 'content-type': 'application/json' } + response = requests.request("POST", self.search_url, headers=headers, data=payload) results = response.json() + if 'organic' in results: results = results['organic'][:self.n_results] string = [] @@ -67,7 +74,7 @@ class SerperDevTool(BaseTool): content = '\n'.join(string) if save_file: - _save_results_to_file(content) + _save_results_to_file(content) return f"\nSearch results: {content}\n" else: return results From 25343727fd4c06eda96bbb5c7d173730063cdae6 Mon Sep 17 00:00:00 2001 From: "ai.flyingwheel" Date: Fri, 19 Jul 2024 23:11:10 +0800 Subject: [PATCH 55/62] fixing serply_api_tool --- .../tools/serply_api_tool/serply_job_search_tool.py | 2 +- .../tools/serply_api_tool/serply_scholar_search_tool.py | 4 ++-- .../tools/serply_api_tool/serply_webpage_to_markdown_tool.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py index 358e312c7..a69ff3de6 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_job_search_tool.py @@ -7,7 +7,7 @@ from crewai_tools.tools.rag.rag_tool import RagTool class SerplyJobSearchToolSchema(BaseModel): - """Input for Serply Scholar Search.""" + """Input for Job Search.""" search_query: str = Field(..., description="Mandatory search query you want to use to fetch jobs postings.") diff --git a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py index 62c3bef7f..a37c36e5f 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_scholar_search_tool.py @@ -13,7 +13,7 @@ class SerplyScholarSearchToolSchema(BaseModel): class SerplyScholarSearchTool(BaseTool): name: str = "Scholar Search" - description: str = "A tool to perform News article search with a search_query." + description: str = "A tool to perform scholarly literature search with a search_query." args_schema: Type[BaseModel] = SerplyScholarSearchToolSchema search_url: str = "https://api.serply.io/v1/scholar/" hl: Optional[str] = "us" @@ -29,7 +29,7 @@ class SerplyScholarSearchTool(BaseTool): """ param: hl (str): host Language code to display results in (reference https://developers.google.com/custom-search/docs/xml_results?hl=en#wsInterfaceLanguages) - proxy_location: (str): Where to get news, specifically for a specific country results. + proxy_location: (str): Specify the proxy location for the search, specifically for a specific country results. ['US', 'CA', 'IE', 'GB', 'FR', 'DE', 'SE', 'IN', 'JP', 'KR', 'SG', 'AU', 'BR'] (defaults to US) """ super().__init__(**kwargs) diff --git a/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py b/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py index 27ffc54ce..5049826c5 100644 --- a/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py +++ b/src/crewai_tools/tools/serply_api_tool/serply_webpage_to_markdown_tool.py @@ -6,7 +6,7 @@ from crewai_tools.tools.rag.rag_tool import RagTool class SerplyWebpageToMarkdownToolSchema(BaseModel): - """Input for Serply Scholar Search.""" + """Input for Serply Search.""" url: str = Field(..., description="Mandatory url you want to use to fetch and convert to markdown") @@ -24,7 +24,7 @@ class SerplyWebpageToMarkdownTool(RagTool): **kwargs ): """ - proxy_location: (str): Where to get news, specifically for a specific country results. + proxy_location: (str): Where to perform the search, specifically for a specific country results. ['US', 'CA', 'IE', 'GB', 'FR', 'DE', 'SE', 'IN', 'JP', 'KR', 'SG', 'AU', 'BR'] (defaults to US) """ super().__init__(**kwargs) From 2df29f3ddec395116720fa809a9f5f0f4dd2d3b8 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Wed, 24 Jul 2024 21:37:22 -0300 Subject: [PATCH 56/62] feat: Add nl2sql tool to run and execute sql queries in databases --- src/crewai_tools/tools/nl2sql/README.md | 0 src/crewai_tools/tools/nl2sql/nl2sql_tool.py | 74 ++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/crewai_tools/tools/nl2sql/README.md create mode 100644 src/crewai_tools/tools/nl2sql/nl2sql_tool.py diff --git a/src/crewai_tools/tools/nl2sql/README.md b/src/crewai_tools/tools/nl2sql/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py new file mode 100644 index 000000000..aec3f0105 --- /dev/null +++ b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py @@ -0,0 +1,74 @@ +from typing import Any, Union + +from crewai_tools import BaseTool +from pydantic import Field +from sqlalchemy import create_engine, text +from sqlalchemy.orm import sessionmaker + + +class NL2SQL(BaseTool): + name: str = "NL2SQL" + description: str = "Converts natural language to SQL queries and executes them." + db_uri: str = Field( + title="Database URI", + description="The URI of the database to connect to.", + ) + tables: list = [] + columns: dict = {} + + def model_post_init(self, __context: Any) -> None: + data = {} + tables = self._fetch_available_tables() + + for table in tables: + table_columns = self._fetch_all_available_columns(table["table_name"]) + data[f'{table["table_name"]}_columns'] = table_columns + + self.tables = tables + self.columns = data + + def _fetch_available_tables(self): + return self.execute_sql( + "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';" + ) + + def _fetch_all_available_columns(self, table_name: str): + return self.execute_sql( + f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{table_name}';" + ) + + def _run(self, sql_query: str): + try: + data = self.execute_sql(sql_query) + except Exception: + data = ( + f"Based on these tables {self.tables} and columns {self.columns}, " + "you can create SQL queries to retrieve data from the database." + f"Get the original request {sql_query} and try to create a SQL query that retrieves the requested data." + ) + + return data + + def execute_sql(self, sql_query: str) -> Union[list, str]: + engine = create_engine(self.db_uri) + Session = sessionmaker(bind=engine) + session = Session() + + try: + result = session.execute(text(sql_query)) + session.commit() + + if result.returns_rows: + columns = result.keys() + data = [dict(zip(columns, row)) for row in result.fetchall()] + return data + else: + return f"Query {sql_query} executed successfully" + + except Exception as e: + session.rollback() + print(f"SQL execution error: {e}") + raise e + + finally: + session.close() From 6fd02cdf82382c651b013d1a7938df413fb8ffc9 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Wed, 24 Jul 2024 21:38:52 -0300 Subject: [PATCH 57/62] feat: remove unecessary code --- src/crewai_tools/tools/nl2sql/nl2sql_tool.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py index aec3f0105..c33411ca8 100644 --- a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py +++ b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py @@ -40,11 +40,11 @@ class NL2SQL(BaseTool): def _run(self, sql_query: str): try: data = self.execute_sql(sql_query) - except Exception: + except Exception as exc: data = ( f"Based on these tables {self.tables} and columns {self.columns}, " "you can create SQL queries to retrieve data from the database." - f"Get the original request {sql_query} and try to create a SQL query that retrieves the requested data." + f"Get the original request {sql_query} and the error {exc} and create the correct SQL query." ) return data @@ -53,7 +53,6 @@ class NL2SQL(BaseTool): engine = create_engine(self.db_uri) Session = sessionmaker(bind=engine) session = Session() - try: result = session.execute(text(sql_query)) session.commit() @@ -64,11 +63,8 @@ class NL2SQL(BaseTool): return data else: return f"Query {sql_query} executed successfully" - except Exception as e: session.rollback() - print(f"SQL execution error: {e}") raise e - finally: session.close() From c372641be811070589da47af400c38af2008f818 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Wed, 24 Jul 2024 21:39:49 -0300 Subject: [PATCH 58/62] feat: format code --- src/crewai_tools/tools/nl2sql/nl2sql_tool.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py index c33411ca8..da70db8ac 100644 --- a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py +++ b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py @@ -63,8 +63,10 @@ class NL2SQL(BaseTool): return data else: return f"Query {sql_query} executed successfully" + except Exception as e: session.rollback() raise e + finally: session.close() From 18a28261a4100fa5ff1ce5328802f914642b8838 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Thu, 25 Jul 2024 15:25:48 -0300 Subject: [PATCH 59/62] docs: Add documentation for NL2SqlTool --- src/crewai_tools/tools/nl2sql/README.md | 74 ++++++++++++++++++ .../tools/nl2sql/images/image-2.png | Bin 0 -> 84676 bytes .../tools/nl2sql/images/image-3.png | Bin 0 -> 83521 bytes .../tools/nl2sql/images/image-4.png | Bin 0 -> 84400 bytes .../tools/nl2sql/images/image-5.png | Bin 0 -> 66131 bytes .../tools/nl2sql/images/image-7.png | Bin 0 -> 24641 bytes .../tools/nl2sql/images/image-9.png | Bin 0 -> 56650 bytes src/crewai_tools/tools/nl2sql/nl2sql_tool.py | 4 +- 8 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/crewai_tools/tools/nl2sql/images/image-2.png create mode 100644 src/crewai_tools/tools/nl2sql/images/image-3.png create mode 100644 src/crewai_tools/tools/nl2sql/images/image-4.png create mode 100644 src/crewai_tools/tools/nl2sql/images/image-5.png create mode 100644 src/crewai_tools/tools/nl2sql/images/image-7.png create mode 100644 src/crewai_tools/tools/nl2sql/images/image-9.png diff --git a/src/crewai_tools/tools/nl2sql/README.md b/src/crewai_tools/tools/nl2sql/README.md index e69de29bb..d0bb82271 100644 --- a/src/crewai_tools/tools/nl2sql/README.md +++ b/src/crewai_tools/tools/nl2sql/README.md @@ -0,0 +1,74 @@ +# NL2SQL Tool + +## Description + +This tool is used to convert natural language to SQL queries. When passsed to the agent it will generate queries and then use them to interact with the database. + +This enables multiple workflows like having an Agent to access the database fetch information based on the goal and then use the information to generate a response, report or any other output. Along with that proivdes the ability for the Agent to update the database based on its goal. + +**Attention**: Make sure that the Agent has access to a Read-Replica or that is okay for the Agent to run insert/update queries on the database. + +## Requirements + +- SqlAlchemy +- Any DB compatible library (e.g. psycopg2, mysql-connector-python) + +## Installation +Install the crewai_tools package +```shell +pip install 'crewai[tools]' +``` + +## Usage + +In order to use the NL2SQLTool, you need to pass the database URI to the tool. The URI should be in the format `dialect+driver://username:password@host:port/database`. + + +```python +from crewai_tools import NL2SQLTool + +# psycopg2 was installed to run this example with PostgreSQL +nl2sql = NL2SQLTool(db_uri="postgresql://example@localhost:5432/test_db") + +@agent +def researcher(self) -> Agent: + return Agent( + config=self.agents_config["researcher"], + allow_delegation=False, + tools=[nl2sql] + ) +``` + +## Example + +The primary task goal was: + +"Retrieve the average, maximum, and minimum monthly revenue for each city, but only include cities that have more than one user. Also, count the number of user in each city and sort the results by the average monthly revenue in descending order" + +So the Agent tried to get information from the DB, the first one is wrong so the Agent tries again and gets the correct information and passes to the next agent. + +![alt text](images/image-2.png) +![alt text](images/image-3.png) + + +The second task goal was: + +"Review the data and create a detailed report, and then create the table on the database with the fields based on the data provided. +Include information on the average, maximum, and minimum monthly revenue for each city, but only include cities that have more than one user. Also, count the number of users in each city and sort the results by the average monthly revenue in descending order." + +Now things start to get interesting, the Agent generates the SQL query to not only create the table but also insert the data into the table. And in the end the Agent still returns the final report which is exactly what was in the database. + +![alt text](images/image-4.png) +![alt text](images/image-5.png) + +![alt text](images/image-9.png) +![alt text](images/image-7.png) + + +This is a simple example of how the NL2SQLTool can be used to interact with the database and generate reports based on the data in the database. + +The Tool provides endless possibilities on the logic of the Agent and how it can interact with the database. + +``` + DB -> Agent -> ... -> Agent -> DB +``` diff --git a/src/crewai_tools/tools/nl2sql/images/image-2.png b/src/crewai_tools/tools/nl2sql/images/image-2.png new file mode 100644 index 0000000000000000000000000000000000000000..b3844f0ddc25e4d407143b7d886f4b3c2ccebc55 GIT binary patch literal 84676 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
mokaBRcn6GcpE7lcTv# zzfr}G`O~zzBHE~&YSZu9M^?75A*U9@mALnL!ZS9F=7NygHTD=}<-aVoy(rusX^T~g z`;+mRYUKOrSSLDnScI6OPhIbXhNwP6;(XeN?>feHle$6?wbgCuKa%0Ey6U-nHCZ$t z&zU&V=Zw8Y9r}%bU(<6co>@YFeQV((E_qwBTGXy3Pbx*9rop5U=9sWA`e{2C1l8_# zJNPP9fFuOfK{kV`tn<$wH81Q5=&G~)bfJ9}n+7omZzHZ&G_BShEy^T;i zZI`$EwVPqpkvea`iN7Yr8jy!?)e+$gJwMCi^J6qy?*5NgVrKU6W3@*#+?&)Yyf5qW zSaeed0gsN%HuKxwi^Y~%P?tCb0;CYFNuG?S&CwWGKVJ4%1KSjY53P?jIkQl?VmOhq zQ=?4Piyc&-8u>TmFLm}SQw3;aHupv)55D5fT;6|HlB)8qm@}HJ&HKeX4pIw}@xxgD zN)?4-z~K`dQy^|Nu{4u6l9UhvyP?Vl*9)r+)?My-bXxpTXMLX| zsg)OQ_m&lS121JjXzQ=FZaS{fa38W7PjP8hk6LFM!O?=?)

sCkMaGpo(tFx)`qEmOh!`BHrJ7~j?g*mWNr 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≶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 literal 0 HcmV?d00001 diff --git a/src/crewai_tools/tools/nl2sql/images/image-5.png b/src/crewai_tools/tools/nl2sql/images/image-5.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d6013dabb306a84987746604fced2606cc3bc3 GIT binary patch literal 66131 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


;CPR)pd0t8Q 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%0A+={fK+X-{t*uH7HS+r{TkP}eZgJ*`p@AFKz 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 afn;v};yKrKlgAFF?^jmPkS~`r_4^M?gl*~o literal 0 HcmV?d00001 diff --git a/src/crewai_tools/tools/nl2sql/images/image-9.png b/src/crewai_tools/tools/nl2sql/images/image-9.png new file mode 100644 index 0000000000000000000000000000000000000000..87f3824342c3aa28496ac5a44f06fad67f0d36fb GIT binary patch literal 56650 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 literal 0 HcmV?d00001 diff --git a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py index da70db8ac..ad93848c4 100644 --- a/src/crewai_tools/tools/nl2sql/nl2sql_tool.py +++ b/src/crewai_tools/tools/nl2sql/nl2sql_tool.py @@ -6,8 +6,8 @@ from sqlalchemy import create_engine, text from sqlalchemy.orm import sessionmaker -class NL2SQL(BaseTool): - name: str = "NL2SQL" +class NL2SQLTool(BaseTool): + name: str = "NL2SQLTool" description: str = "Converts natural language to SQL queries and executes them." db_uri: str = Field( title="Database URI", From b343c71b9bcecf1b77aa8a98eb79e0bf5d7897a4 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Tue, 30 Jul 2024 22:17:23 -0300 Subject: [PATCH 60/62] feat: Add Dall-E tool to generate images --- src/crewai_tools/tools/dalle_tool/README.MD | 0 .../tools/dalle_tool/dalle_tool.py | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/crewai_tools/tools/dalle_tool/README.MD create mode 100644 src/crewai_tools/tools/dalle_tool/dalle_tool.py diff --git a/src/crewai_tools/tools/dalle_tool/README.MD b/src/crewai_tools/tools/dalle_tool/README.MD new file mode 100644 index 000000000..e69de29bb diff --git a/src/crewai_tools/tools/dalle_tool/dalle_tool.py b/src/crewai_tools/tools/dalle_tool/dalle_tool.py new file mode 100644 index 000000000..a4f7738a6 --- /dev/null +++ b/src/crewai_tools/tools/dalle_tool/dalle_tool.py @@ -0,0 +1,48 @@ +import json +from typing import Type + +from crewai_tools.tools.base_tool import BaseTool +from openai import OpenAI +from pydantic.v1 import BaseModel + + +class ImagePromptSchema(BaseModel): + """Input for Dall-E Tool.""" + + image_description: str = "Description of the image to be generated by Dall-E." + + +class DallETool(BaseTool): + name: str = "Dall-E Tool" + description: str = "Generates images using OpenAI's Dall-E model." + args_schema: Type[BaseModel] = ImagePromptSchema + + model: str = "dall-e-3" + size: str = "1024x1024" + quality: str = "standard" + n: int = 1 + + def _run(self, **kwargs) -> str: + client = OpenAI() + + image_description = kwargs.get("image_description") + + if not image_description: + return "Image description is required." + + response = client.images.generate( + model=self.model, + prompt=image_description, + size=self.size, + quality=self.quality, + n=self.n, + ) + + image_data = json.dumps( + { + "image_url": response.data[0].url, + "image_description": response.data[0].revised_prompt, + } + ) + + return image_data From 0070df7451a1a79b33e655628ab2f0d324d6c3eb Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Tue, 30 Jul 2024 22:29:45 -0300 Subject: [PATCH 61/62] docs: Add documentation for the DallETool --- src/crewai_tools/tools/dalle_tool/README.MD | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/crewai_tools/tools/dalle_tool/README.MD b/src/crewai_tools/tools/dalle_tool/README.MD index e69de29bb..a315c7c10 100644 --- a/src/crewai_tools/tools/dalle_tool/README.MD +++ b/src/crewai_tools/tools/dalle_tool/README.MD @@ -0,0 +1,41 @@ +# DALL-E Tool + +## Description +This tool is used to give the Agent the ability to generate images using the DALL-E model. It is a transformer-based model that generates images from textual descriptions. This tool allows the Agent to generate images based on the text input provided by the user. + +## Installation +Install the crewai_tools package +```shell +pip install 'crewai[tools]' +``` + +## Example + +Remember that when using this tool, the text must be generated by the Agent itself. The text must be a description of the image you want to generate. + +```python +from crewai_tools import DallETool + +Agent( + ... + tools=[DallETool()], +) +``` + +If needed you can also tweak the parameters of the DALL-E model by passing them as arguments to the `DallETool` class. For example: + +```python +from crewai_tools import DallETool + +dalle_tool = DallETool(model: str = "dall-e-3", + size: str = "1024x1024", + quality: str = "standard", + n: int = 1) + +Agent( + ... + tools=[dalle_tool] +) +``` + +The parameter are based on the `client.images.generate` method from the OpenAI API. For more information on the parameters, please refer to the [OpenAI API documentation](https://platform.openai.com/docs/guides/images/introduction?lang=python). From 4835c2bf68bc98bd28e29bee22a4d7d5b6b0cd49 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Wed, 31 Jul 2024 17:10:26 -0300 Subject: [PATCH 62/62] feat: Add Vision tool to the CrewAI tool --- src/crewai_tools/__init__.py | 10 +- src/crewai_tools/tools/__init__.py | 24 +++-- src/crewai_tools/tools/vision_tool/README.md | 30 ++++++ .../tools/vision_tool/vision_tool.py | 93 +++++++++++++++++++ 4 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 src/crewai_tools/tools/vision_tool/README.md create mode 100644 src/crewai_tools/tools/vision_tool/vision_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index a049cdc5b..b049d630d 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -17,23 +17,25 @@ from .tools import ( LlamaIndexTool, MDXSearchTool, MultiOnTool, + NL2SQLTool, PDFSearchTool, PGSearchTool, RagTool, ScrapeElementFromWebsiteTool, - ScrapflyScrapeWebsiteTool, ScrapeWebsiteTool, + ScrapflyScrapeWebsiteTool, SeleniumScrapingTool, SerperDevTool, - SerplyWebSearchTool, + SerplyJobSearchTool, SerplyNewsSearchTool, SerplyScholarSearchTool, SerplyWebpageToMarkdownTool, - SerplyJobSearchTool, + SerplyWebSearchTool, TXTSearchTool, + VisionTool, WebsiteSearchTool, XMLSearchTool, YoutubeChannelSearchTool, - YoutubeVideoSearchTool + YoutubeVideoSearchTool, ) from .tools.base_tool import BaseTool, Tool, tool diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index a72fda277..483ebda21 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -8,14 +8,19 @@ from .directory_search_tool.directory_search_tool import DirectorySearchTool from .docx_search_tool.docx_search_tool import DOCXSearchTool from .exa_tools.exa_search_tool import EXASearchTool from .file_read_tool.file_read_tool import FileReadTool -from .firecrawl_crawl_website_tool.firecrawl_crawl_website_tool import FirecrawlCrawlWebsiteTool -from .firecrawl_scrape_website_tool.firecrawl_scrape_website_tool import FirecrawlScrapeWebsiteTool +from .firecrawl_crawl_website_tool.firecrawl_crawl_website_tool import ( + FirecrawlCrawlWebsiteTool, +) +from .firecrawl_scrape_website_tool.firecrawl_scrape_website_tool import ( + FirecrawlScrapeWebsiteTool, +) from .firecrawl_search_tool.firecrawl_search_tool import FirecrawlSearchTool from .github_search_tool.github_search_tool import GithubSearchTool from .json_search_tool.json_search_tool import JSONSearchTool from .llamaindex_tool.llamaindex_tool import LlamaIndexTool from .mdx_seach_tool.mdx_search_tool import MDXSearchTool from .multion_tool.multion_tool import MultiOnTool +from .nl2sql.nl2sql_tool import NL2SQLTool from .pdf_search_tool.pdf_search_tool import PDFSearchTool from .pg_seach_tool.pg_search_tool import PGSearchTool from .rag.rag_tool import RagTool @@ -23,17 +28,22 @@ from .scrape_element_from_website.scrape_element_from_website import ( ScrapeElementFromWebsiteTool, ) from .scrape_website_tool.scrape_website_tool import ScrapeWebsiteTool -from .scrapfly_scrape_website_tool.scrapfly_scrape_website_tool import ScrapflyScrapeWebsiteTool +from .scrapfly_scrape_website_tool.scrapfly_scrape_website_tool import ( + ScrapflyScrapeWebsiteTool, +) from .selenium_scraping_tool.selenium_scraping_tool import SeleniumScrapingTool from .serper_dev_tool.serper_dev_tool import SerperDevTool -from .serply_api_tool.serply_web_search_tool import SerplyWebSearchTool +from .serply_api_tool.serply_job_search_tool import SerplyJobSearchTool from .serply_api_tool.serply_news_search_tool import SerplyNewsSearchTool from .serply_api_tool.serply_scholar_search_tool import SerplyScholarSearchTool +from .serply_api_tool.serply_web_search_tool import SerplyWebSearchTool from .serply_api_tool.serply_webpage_to_markdown_tool import SerplyWebpageToMarkdownTool -from .serply_api_tool.serply_job_search_tool import SerplyJobSearchTool +from .spider_tool.spider_tool import SpiderTool from .txt_search_tool.txt_search_tool import TXTSearchTool +from .vision_tool.vision_tool import VisionTool from .website_search.website_search_tool import WebsiteSearchTool from .xml_search_tool.xml_search_tool import XMLSearchTool -from .youtube_channel_search_tool.youtube_channel_search_tool import YoutubeChannelSearchTool +from .youtube_channel_search_tool.youtube_channel_search_tool import ( + YoutubeChannelSearchTool, +) from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool -from .spider_tool.spider_tool import SpiderTool diff --git a/src/crewai_tools/tools/vision_tool/README.md b/src/crewai_tools/tools/vision_tool/README.md new file mode 100644 index 000000000..bf7ab7486 --- /dev/null +++ b/src/crewai_tools/tools/vision_tool/README.md @@ -0,0 +1,30 @@ +# Vision Tool + +## Description + +This tool is used to extract text from images. When passed to the agent it will extract the text from the image and then use it to generate a response, report or any other output. The URL or the PATH of the image should be passed to the Agent. + + +## Installation +Install the crewai_tools package +```shell +pip install 'crewai[tools]' +``` + +## Usage + +In order to use the VisionTool, the OpenAI API key should be set in the environment variable `OPENAI_API_KEY`. + +```python +from crewai_tools import VisionTool + +vision_tool = VisionTool() + +@agent +def researcher(self) -> Agent: + return Agent( + config=self.agents_config["researcher"], + allow_delegation=False, + tools=[vision_tool] + ) +``` diff --git a/src/crewai_tools/tools/vision_tool/vision_tool.py b/src/crewai_tools/tools/vision_tool/vision_tool.py new file mode 100644 index 000000000..a9abd5c43 --- /dev/null +++ b/src/crewai_tools/tools/vision_tool/vision_tool.py @@ -0,0 +1,93 @@ +import base64 +from typing import Type + +import requests +from crewai_tools.tools.base_tool import BaseTool +from openai import OpenAI +from pydantic.v1 import BaseModel + + +class ImagePromptSchema(BaseModel): + """Input for Vision Tool.""" + + image_path_url: str = "The image path or URL." + + +class VisionTool(BaseTool): + name: str = "Vision Tool" + description: str = ( + "This tool uses OpenAI's Vision API to describe the contents of an image." + ) + args_schema: Type[BaseModel] = ImagePromptSchema + + def _run_web_hosted_images(self, client, image_path_url: str) -> str: + response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": "What's in this image?"}, + { + "type": "image_url", + "image_url": {"url": image_path_url}, + }, + ], + } + ], + max_tokens=300, + ) + + return response.choices[0].message.content + + def _run_local_images(self, client, image_path_url: str) -> str: + base64_image = self._encode_image(image_path_url) + + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {client.api_key}", + } + + payload = { + "model": "gpt-4o-mini", + "messages": [ + { + "role": "user", + "content": [ + {"type": "text", "text": "What's in this image?"}, + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{base64_image}" + }, + }, + ], + } + ], + "max_tokens": 300, + } + + response = requests.post( + "https://api.openai.com/v1/chat/completions", headers=headers, json=payload + ) + + return response.json()["choices"][0]["message"]["content"] + + def _run(self, **kwargs) -> str: + client = OpenAI() + + image_path_url = kwargs.get("image_path_url") + + if not image_path_url: + return "Image Path or URL is required." + + if "http" in image_path_url: + image_description = self._run_web_hosted_images(client, image_path_url) + else: + image_description = self._run_local_images(client, image_path_url) + + return image_description + + def _encode_image(self, image_path: str): + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode("utf-8")