Merge pull request #149 from tanys123/feat/serpapi-tools

feat: Add Google Search and Google Shopping tools
This commit is contained in:
João Moura
2024-12-27 21:48:20 -03:00
committed by GitHub
6 changed files with 156 additions and 0 deletions

View File

@@ -43,4 +43,6 @@ from .tools import (
YoutubeChannelSearchTool,
YoutubeVideoSearchTool,
WeaviateVectorSearchTool,
SerpApiGoogleSearchTool,
SerpApiGoogleShoppingTool,
)

View File

@@ -52,3 +52,5 @@ from .youtube_channel_search_tool.youtube_channel_search_tool import (
)
from .youtube_video_search_tool.youtube_video_search_tool import YoutubeVideoSearchTool
from .weaviate_tool.vector_search import WeaviateVectorSearchTool
from .serpapi_tool.serpapi_google_search_tool import SerpApiGoogleSearchTool
from .serpapi_tool.serpapi_google_shopping_tool import SerpApiGoogleShoppingTool

View File

@@ -0,0 +1,32 @@
# SerpApi Tools
## Description
[SerpApi](https://serpapi.com/) tools are built for searching information in the internet. It currently supports:
- Google Search
- Google Shopping
To successfully make use of SerpApi tools, you have to have `SERPAPI_API_KEY` set in the environment. To get the API key, register a free account at [SerpApi](https://serpapi.com/).
## Installation
To start using the SerpApi Tools, you must first install the `crewai_tools` package. This can be easily done with the following command:
```shell
pip install 'crewai[tools]'
```
## Examples
The following example demonstrates how to initialize the tool
### Google Search
```python
from crewai_tools import SerpApiGoogleSearchTool
tool = SerpApiGoogleSearchTool()
```
### Google Shopping
```python
from crewai_tools import SerpApiGoogleShoppingTool
tool = SerpApiGoogleShoppingTool()
```

View File

@@ -0,0 +1,38 @@
import os
import re
from typing import Optional, Any, Union
from crewai.tools import BaseTool
class SerpApiBaseTool(BaseTool):
"""Base class for SerpApi functionality with shared capabilities."""
client: Optional[Any] = None
def __init__(self, **kwargs):
super().__init__(**kwargs)
try:
from serpapi import Client
except ImportError:
raise ImportError(
"`serpapi` package not found, please install with `pip install serpapi`"
)
api_key = os.getenv("SERPAPI_API_KEY")
if not api_key:
raise ValueError(
"Missing API key, you can get the key from https://serpapi.com/manage-api-key"
)
self.client = Client(api_key=api_key)
def _omit_fields(self, data: Union[dict, list], omit_patterns: list[str]) -> None:
if isinstance(data, dict):
for field in list(data.keys()):
if any(re.compile(p).match(field) for p in omit_patterns):
data.pop(field, None)
else:
if isinstance(data[field], (dict, list)):
self._omit_fields(data[field], omit_patterns)
elif isinstance(data, list):
for item in data:
self._omit_fields(item, omit_patterns)

View File

@@ -0,0 +1,40 @@
from typing import Any, Type, Optional
import re
from pydantic import BaseModel, Field
from .serpapi_base_tool import SerpApiBaseTool
from serpapi import HTTPError
class SerpApiGoogleSearchToolSchema(BaseModel):
"""Input for Google Search."""
search_query: str = Field(..., description="Mandatory search query you want to use to Google search.")
location: Optional[str] = Field(None, description="Location you want the search to be performed in.")
class SerpApiGoogleSearchTool(SerpApiBaseTool):
name: str = "Google Search"
description: str = (
"A tool to perform to perform a Google search with a search_query."
)
args_schema: Type[BaseModel] = SerpApiGoogleSearchToolSchema
def _run(
self,
**kwargs: Any,
) -> Any:
try:
results = self.client.search({
"q": kwargs.get("search_query"),
"location": kwargs.get("location"),
}).as_dict()
self._omit_fields(
results,
[r"search_metadata", r"search_parameters", r"serpapi_.+", r".+_token", r"displayed_link", r"pagination"]
)
return results
except HTTPError as e:
return f"An error occurred: {str(e)}. Some parameters may be invalid."

View File

@@ -0,0 +1,42 @@
from typing import Any, Type, Optional
import re
from pydantic import BaseModel, Field
from .serpapi_base_tool import SerpApiBaseTool
from serpapi import HTTPError
class SerpApiGoogleShoppingToolSchema(BaseModel):
"""Input for Google Shopping."""
search_query: str = Field(..., description="Mandatory search query you want to use to Google shopping.")
location: Optional[str] = Field(None, description="Location you want the search to be performed in.")
class SerpApiGoogleShoppingTool(SerpApiBaseTool):
name: str = "Google Shopping"
description: str = (
"A tool to perform search on Google shopping with a search_query."
)
args_schema: Type[BaseModel] = SerpApiGoogleShoppingToolSchema
def _run(
self,
**kwargs: Any,
) -> Any:
try:
results = self.client.search({
"engine": "google_shopping",
"q": kwargs.get("search_query"),
"location": kwargs.get("location")
}).as_dict()
self._omit_fields(
results,
[r"search_metadata", r"search_parameters", r"serpapi_.+", r"filters", r"pagination"]
)
return results
except HTTPError as e:
return f"An error occurred: {str(e)}. Some parameters may be invalid."