Merge pull request #549 from Kingtous/main
feat: add Baidu, DuckDuckGo search tool and optional config
This commit is contained in:
commit
c4d628cc4e
@ -7,8 +7,9 @@ from app.prompt.manus import NEXT_STEP_PROMPT, SYSTEM_PROMPT
|
|||||||
from app.tool import Terminate, ToolCollection
|
from app.tool import Terminate, ToolCollection
|
||||||
from app.tool.browser_use_tool import BrowserUseTool
|
from app.tool.browser_use_tool import BrowserUseTool
|
||||||
from app.tool.file_saver import FileSaver
|
from app.tool.file_saver import FileSaver
|
||||||
from app.tool.google_search import GoogleSearch
|
from app.tool.web_search import WebSearch
|
||||||
from app.tool.python_execute import PythonExecute
|
from app.tool.python_execute import PythonExecute
|
||||||
|
from app.config import config
|
||||||
|
|
||||||
|
|
||||||
class Manus(ToolCallAgent):
|
class Manus(ToolCallAgent):
|
||||||
@ -34,7 +35,7 @@ class Manus(ToolCallAgent):
|
|||||||
# Add general-purpose tools to the tool collection
|
# Add general-purpose tools to the tool collection
|
||||||
available_tools: ToolCollection = Field(
|
available_tools: ToolCollection = Field(
|
||||||
default_factory=lambda: ToolCollection(
|
default_factory=lambda: ToolCollection(
|
||||||
PythonExecute(), GoogleSearch(), BrowserUseTool(), FileSaver(), Terminate()
|
PythonExecute(), WebSearch(), BrowserUseTool(), FileSaver(), Terminate()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ class ProxySettings(BaseModel):
|
|||||||
username: Optional[str] = Field(None, description="Proxy username")
|
username: Optional[str] = Field(None, description="Proxy username")
|
||||||
password: Optional[str] = Field(None, description="Proxy password")
|
password: Optional[str] = Field(None, description="Proxy password")
|
||||||
|
|
||||||
|
class SearchSettings(BaseModel):
|
||||||
|
engine: str = Field(default='Google', description="Search engine the llm to use")
|
||||||
|
|
||||||
class BrowserSettings(BaseModel):
|
class BrowserSettings(BaseModel):
|
||||||
headless: bool = Field(False, description="Whether to run browser in headless mode")
|
headless: bool = Field(False, description="Whether to run browser in headless mode")
|
||||||
@ -58,6 +60,9 @@ class AppConfig(BaseModel):
|
|||||||
browser_config: Optional[BrowserSettings] = Field(
|
browser_config: Optional[BrowserSettings] = Field(
|
||||||
None, description="Browser configuration"
|
None, description="Browser configuration"
|
||||||
)
|
)
|
||||||
|
search_config: Optional[SearchSettings] = Field(
|
||||||
|
None, description="Search configuration"
|
||||||
|
)
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
arbitrary_types_allowed = True
|
arbitrary_types_allowed = True
|
||||||
@ -149,6 +154,11 @@ class Config:
|
|||||||
if valid_browser_params:
|
if valid_browser_params:
|
||||||
browser_settings = BrowserSettings(**valid_browser_params)
|
browser_settings = BrowserSettings(**valid_browser_params)
|
||||||
|
|
||||||
|
search_config = raw_config.get("search", {})
|
||||||
|
search_settings = None
|
||||||
|
if search_config:
|
||||||
|
search_settings = SearchSettings(**search_config)
|
||||||
|
|
||||||
config_dict = {
|
config_dict = {
|
||||||
"llm": {
|
"llm": {
|
||||||
"default": default_settings,
|
"default": default_settings,
|
||||||
@ -158,6 +168,7 @@ class Config:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"browser_config": browser_settings,
|
"browser_config": browser_settings,
|
||||||
|
"search_config": search_settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
self._config = AppConfig(**config_dict)
|
self._config = AppConfig(**config_dict)
|
||||||
@ -170,5 +181,9 @@ class Config:
|
|||||||
def browser_config(self) -> Optional[BrowserSettings]:
|
def browser_config(self) -> Optional[BrowserSettings]:
|
||||||
return self._config.browser_config
|
return self._config.browser_config
|
||||||
|
|
||||||
|
@property
|
||||||
|
def search_config(self) -> Optional[SearchSettings]:
|
||||||
|
return self._config.search_config
|
||||||
|
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
|
@ -8,7 +8,7 @@ FileSaver: Save files locally, such as txt, py, html, etc.
|
|||||||
|
|
||||||
BrowserUseTool: Open, browse, and use web browsers.If you open a local HTML file, you must provide the absolute path to the file.
|
BrowserUseTool: Open, browse, and use web browsers.If you open a local HTML file, you must provide the absolute path to the file.
|
||||||
|
|
||||||
GoogleSearch: Perform web information retrieval
|
WebSearch: Perform web information retrieval
|
||||||
|
|
||||||
Terminate: End the current interaction when the task is complete or when you need additional information from the user. Use this tool to signal that you've finished addressing the user's request or need clarification before proceeding further.
|
Terminate: End the current interaction when the task is complete or when you need additional information from the user. Use this tool to signal that you've finished addressing the user's request or need clarification before proceeding further.
|
||||||
|
|
||||||
|
12
app/tool/search/__init__.py
Normal file
12
app/tool/search/__init__.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from app.tool.search.base import WebSearchEngine
|
||||||
|
from app.tool.search.baidu_search import BaiduSearchEngine
|
||||||
|
from app.tool.search.duckduckgo_search import DuckDuckGoSearchEngine
|
||||||
|
from app.tool.search.google_search import GoogleSearchEngine
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"WebSearchEngine",
|
||||||
|
"BaiduSearchEngine",
|
||||||
|
"DuckDuckGoSearchEngine",
|
||||||
|
"GoogleSearchEngine",
|
||||||
|
]
|
9
app/tool/search/baidu_search.py
Normal file
9
app/tool/search/baidu_search.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from baidusearch.baidusearch import search
|
||||||
|
from app.tool.search.base import WebSearchEngine
|
||||||
|
|
||||||
|
|
||||||
|
class BaiduSearchEngine(WebSearchEngine):
|
||||||
|
|
||||||
|
def perform_search(self, query, num_results = 10, *args, **kwargs):
|
||||||
|
"""Baidu search engine."""
|
||||||
|
return search(query, num_results=num_results)
|
15
app/tool/search/base.py
Normal file
15
app/tool/search/base.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class WebSearchEngine(object):
|
||||||
|
def perform_search(self, query: str, num_results: int = 10, *args, **kwargs) -> list[dict]:
|
||||||
|
"""
|
||||||
|
Perform a web search and return a list of URLs.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query (str): The search query to submit to the search engine.
|
||||||
|
num_results (int, optional): The number of search results to return. Default is 10.
|
||||||
|
args: Additional arguments.
|
||||||
|
kwargs: Additional keyword arguments.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List: A list of dict matching the search query.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
9
app/tool/search/duckduckgo_search.py
Normal file
9
app/tool/search/duckduckgo_search.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from duckduckgo_search import DDGS
|
||||||
|
from app.tool.search.base import WebSearchEngine
|
||||||
|
|
||||||
|
|
||||||
|
class DuckDuckGoSearchEngine(WebSearchEngine):
|
||||||
|
|
||||||
|
async def perform_search(self, query, num_results = 10, *args, **kwargs):
|
||||||
|
"""DuckDuckGo search engine."""
|
||||||
|
return DDGS.text(query, num_results=num_results)
|
8
app/tool/search/google_search.py
Normal file
8
app/tool/search/google_search.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from app.tool.search.base import WebSearchEngine
|
||||||
|
from googlesearch import search
|
||||||
|
|
||||||
|
class GoogleSearchEngine(WebSearchEngine):
|
||||||
|
|
||||||
|
def perform_search(self, query, num_results = 10, *args, **kwargs):
|
||||||
|
"""Google search engine."""
|
||||||
|
return search(query, num_results=num_results)
|
@ -1,14 +1,14 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from googlesearch import search
|
|
||||||
|
|
||||||
from app.tool.base import BaseTool
|
from app.tool.base import BaseTool
|
||||||
|
from app.config import config
|
||||||
|
from app.tool.search import WebSearchEngine, BaiduSearchEngine, GoogleSearchEngine, DuckDuckGoSearchEngine
|
||||||
|
|
||||||
|
|
||||||
class GoogleSearch(BaseTool):
|
class WebSearch(BaseTool):
|
||||||
name: str = "google_search"
|
name: str = "web_search"
|
||||||
description: str = """Perform a Google search and return a list of relevant links.
|
description: str = """Perform a web search and return a list of relevant links.
|
||||||
Use this tool when you need to find information on the web, get up-to-date data, or research specific topics.
|
Use this tool when you need to find information on the web, get up-to-date data, or research specific topics.
|
||||||
The tool returns a list of URLs that match the search query.
|
The tool returns a list of URLs that match the search query.
|
||||||
"""
|
"""
|
||||||
@ -17,7 +17,7 @@ The tool returns a list of URLs that match the search query.
|
|||||||
"properties": {
|
"properties": {
|
||||||
"query": {
|
"query": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "(required) The search query to submit to Google.",
|
"description": "(required) The search query to submit to the search engine.",
|
||||||
},
|
},
|
||||||
"num_results": {
|
"num_results": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@ -27,13 +27,18 @@ The tool returns a list of URLs that match the search query.
|
|||||||
},
|
},
|
||||||
"required": ["query"],
|
"required": ["query"],
|
||||||
}
|
}
|
||||||
|
_search_engine: dict[str, WebSearchEngine] = {
|
||||||
|
"google": GoogleSearchEngine(),
|
||||||
|
"baidu": BaiduSearchEngine(),
|
||||||
|
"duckduckgo": DuckDuckGoSearchEngine(),
|
||||||
|
}
|
||||||
|
|
||||||
async def execute(self, query: str, num_results: int = 10) -> List[str]:
|
async def execute(self, query: str, num_results: int = 10) -> List[str]:
|
||||||
"""
|
"""
|
||||||
Execute a Google search and return a list of URLs.
|
Execute a Web search and return a list of URLs.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
query (str): The search query to submit to Google.
|
query (str): The search query to submit to the search engine.
|
||||||
num_results (int, optional): The number of search results to return. Default is 10.
|
num_results (int, optional): The number of search results to return. Default is 10.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -41,8 +46,18 @@ The tool returns a list of URLs that match the search query.
|
|||||||
"""
|
"""
|
||||||
# Run the search in a thread pool to prevent blocking
|
# Run the search in a thread pool to prevent blocking
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
search_engine = self.get_search_engine()
|
||||||
links = await loop.run_in_executor(
|
links = await loop.run_in_executor(
|
||||||
None, lambda: list(search(query, num_results=num_results))
|
None, lambda: list(search_engine.perform_search(query, num_results=num_results))
|
||||||
)
|
)
|
||||||
|
|
||||||
return links
|
return links
|
||||||
|
|
||||||
|
def get_search_engine(self) -> WebSearchEngine:
|
||||||
|
"""Determines the search engine to use based on the configuration."""
|
||||||
|
default_engine = self._search_engine.get("google")
|
||||||
|
if config.search_config is None:
|
||||||
|
return default_engine
|
||||||
|
else:
|
||||||
|
engine = config.search_config.engine.lower()
|
||||||
|
return self._search_engine.get(engine, default_engine)
|
@ -42,3 +42,8 @@ api_key = "sk-..."
|
|||||||
# server = "http://proxy-server:port"
|
# server = "http://proxy-server:port"
|
||||||
# username = "proxy-username"
|
# username = "proxy-username"
|
||||||
# password = "proxy-password"
|
# password = "proxy-password"
|
||||||
|
|
||||||
|
# Optional configuration, Search settings.
|
||||||
|
# [search]
|
||||||
|
# Search engine for agent to use. Default is "Google", can be set to "Baidu" or "DuckDuckGo".
|
||||||
|
#engine = "Google"
|
@ -15,6 +15,8 @@ uvicorn~=0.34.0
|
|||||||
unidiff~=0.7.5
|
unidiff~=0.7.5
|
||||||
browser-use~=0.1.40
|
browser-use~=0.1.40
|
||||||
googlesearch-python~=1.3.0
|
googlesearch-python~=1.3.0
|
||||||
|
baidusearch~=1.0.3
|
||||||
|
duckduckgo_search~=7.5.1
|
||||||
|
|
||||||
aiofiles~=24.1.0
|
aiofiles~=24.1.0
|
||||||
pydantic_core~=2.27.2
|
pydantic_core~=2.27.2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user