Duibonduil commited on
Commit
6bf2a1e
·
verified ·
1 Parent(s): 5bfc337

Upload 2 files

Browse files
examples/tools/apis/actions.py ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+
3
+ import json
4
+ import os
5
+
6
+ import requests
7
+
8
+ from typing import Tuple, Any, List, Dict
9
+
10
+ from examples.tools.tool_action import SearchAction
11
+ from aworld.core.tool.action_factory import ActionFactory
12
+ from aworld.core.common import ActionModel, ActionResult
13
+ from aworld.logs.util import logger
14
+ from aworld.utils import import_package
15
+ from aworld.core.tool.action import ExecutableAction
16
+
17
+
18
+ @ActionFactory.register(name=SearchAction.WIKI.value.name,
19
+ desc=SearchAction.WIKI.value.desc,
20
+ tool_name='search_api')
21
+ class SearchWiki(ExecutableAction):
22
+ def __init__(self):
23
+ import_package("wikipedia")
24
+
25
+ def act(self, action: ActionModel, **kwargs) -> Tuple[ActionResult, Any]:
26
+ import wikipedia
27
+
28
+ query = action.params.get("query")
29
+ logger.info(f"Calling search_wiki api with query: {query}")
30
+
31
+ result: str = ''
32
+ try:
33
+ page = wikipedia.page(query)
34
+ result_dict = {
35
+ 'url': page.url,
36
+ 'title': page.title,
37
+ 'content': page.content,
38
+ }
39
+ result = str(result_dict)
40
+ except wikipedia.exceptions.DisambiguationError as e:
41
+ result = wikipedia.summary(
42
+ e.options[0], sentences=5, auto_suggest=False
43
+ )
44
+ except wikipedia.exceptions.PageError:
45
+ result = (
46
+ "There is no page in Wikipedia corresponding to entity "
47
+ f"{query}, please specify another word to describe the"
48
+ " entity to be searched."
49
+ )
50
+ except Exception as e:
51
+ logger.error(f"An exception occurred during the search: {e}")
52
+ result = f"An exception occurred during the search: {e}"
53
+ logger.debug(f"wiki result: {result}")
54
+ return ActionResult(content=result, keep=True, is_done=True), None
55
+
56
+
57
+ @ActionFactory.register(name=SearchAction.DUCK_GO.value.name,
58
+ desc=SearchAction.DUCK_GO.value.desc,
59
+ tool_name="search_api")
60
+ class Duckduckgo(ExecutableAction):
61
+ def __init__(self):
62
+ import_package("duckduckgo_search")
63
+
64
+ def act(self, action: ActionModel, **kwargs) -> Tuple[ActionResult, Any]:
65
+ r"""Use DuckDuckGo search engine to search information for
66
+ the given query.
67
+
68
+ This function queries the DuckDuckGo API for related topics to
69
+ the given search term. The results are formatted into a list of
70
+ dictionaries, each representing a search result.
71
+
72
+ Args:
73
+ query (str): The query to be searched.
74
+ source (str): The type of information to query (e.g., "text",
75
+ "images", "videos"). Defaults to "text".
76
+ max_results (int): Max number of results, defaults to `5`.
77
+
78
+ Returns:
79
+ List[Dict[str, Any]]: A list of dictionaries where each dictionary
80
+ represents a search result.
81
+ """
82
+
83
+ from duckduckgo_search import DDGS
84
+
85
+ params = action.params
86
+ query = params.get("query")
87
+ max_results = params.get("max_results", 5)
88
+ source = params.get("source", "text")
89
+
90
+ logger.debug(f"Calling search_duckduckgo function with query: {query}")
91
+
92
+ ddgs = DDGS()
93
+ responses: List[Dict[str, Any]] = []
94
+
95
+ if source == "text":
96
+ try:
97
+ results = ddgs.text(keywords=query, max_results=max_results)
98
+ except Exception as e:
99
+ # Handle specific exceptions or general request exceptions
100
+ responses.append({"error": f"duckduckgo search failed.{e}"})
101
+ return ActionResult(content="duckduckgo search failed", keep=True), responses
102
+
103
+ for i, result in enumerate(results, start=1):
104
+ # Creating a response object with a similar structure
105
+ response = {
106
+ "result_id": i,
107
+ "title": result["title"],
108
+ "description": result["body"],
109
+ "url": result["href"],
110
+ }
111
+ responses.append(response)
112
+ elif source == "images":
113
+ try:
114
+ results = ddgs.images(keywords=query, max_results=max_results)
115
+ except Exception as e:
116
+ # Handle specific exceptions or general request exceptions
117
+ responses.append({"error": f"duckduckgo search failed.{e}"})
118
+ return ActionResult(content="duckduckgo search failed", keep=True), responses
119
+
120
+ # Iterate over results found
121
+ for i, result in enumerate(results, start=1):
122
+ # Creating a response object with a similar structure
123
+ response = {
124
+ "result_id": i,
125
+ "title": result["title"],
126
+ "image": result["image"],
127
+ "url": result["url"],
128
+ "source": result["source"],
129
+ }
130
+ responses.append(response)
131
+ elif source == "videos":
132
+ try:
133
+ results = ddgs.videos(keywords=query, max_results=max_results)
134
+ except Exception as e:
135
+ # Handle specific exceptions or general request exceptions
136
+ responses.append({"error": f"duckduckgo search failed.{e}"})
137
+ return ActionResult(content="duckduckgo search failed", keep=True), responses
138
+
139
+ # Iterate over results found
140
+ for i, result in enumerate(results, start=1):
141
+ # Creating a response object with a similar structure
142
+ response = {
143
+ "result_id": i,
144
+ "title": result["title"],
145
+ "description": result["description"],
146
+ "embed_url": result["embed_url"],
147
+ "publisher": result["publisher"],
148
+ "duration": result["duration"],
149
+ "published": result["published"],
150
+ }
151
+ responses.append(response)
152
+ logger.debug(f"Search results: {responses}")
153
+ return ActionResult(content=json.dumps(responses), keep=True, is_done=True), None
154
+
155
+
156
+ @ActionFactory.register(name=SearchAction.GOOGLE.value.name,
157
+ desc=SearchAction.GOOGLE.value.desc,
158
+ tool_name="search_api")
159
+ class SearchGoogle(ExecutableAction):
160
+ def act(self, action: ActionModel, **kwargs) -> Tuple[ActionResult, Any]:
161
+ query = action.params.get("query")
162
+ num_result_pages = action.params.get("num_result_pages", 6)
163
+ # https://developers.google.com/custom-search/v1/overview
164
+ api_key = action.params.get("api_key", os.environ.get("GOOGLE_API_KEY"))
165
+ # https://cse.google.com/cse/all
166
+ engine_id = action.params.get("engine_id", os.environ.get("GOOGLE_ENGINE_ID"))
167
+ logger.debug(f"Calling search_google function with query: {query}")
168
+
169
+ # Using the first page
170
+ start_page_idx = 1
171
+ # Different language may get different result
172
+ search_language = "en"
173
+ # How many pages to return
174
+ num_result_pages = num_result_pages
175
+ # Constructing the URL
176
+ # Doc: https://developers.google.com/custom-search/v1/using_rest
177
+ url = f"https://www.googleapis.com/customsearch/v1?key={api_key}&cx={engine_id}&q={query}&start={start_page_idx}&lr={search_language}&num={num_result_pages}"
178
+ responses = []
179
+ try:
180
+ result = requests.get(url)
181
+ result.raise_for_status()
182
+ data = result.json()
183
+
184
+ # Get the result items
185
+ if "items" in data:
186
+ search_items = data.get("items")
187
+
188
+ for i, search_item in enumerate(search_items, start=1):
189
+ # Check metatags are present
190
+ if "pagemap" not in search_item:
191
+ continue
192
+ if "metatags" not in search_item["pagemap"]:
193
+ continue
194
+ if "og:description" in search_item["pagemap"]["metatags"][0]:
195
+ long_description = search_item["pagemap"]["metatags"][0]["og:description"]
196
+ else:
197
+ long_description = "N/A"
198
+ # Get the page title
199
+ title = search_item.get("title")
200
+ # Page snippet
201
+ snippet = search_item.get("snippet")
202
+
203
+ # Extract the page url
204
+ link = search_item.get("link")
205
+ response = {
206
+ "result_id": i,
207
+ "title": title,
208
+ "description": snippet,
209
+ "long_description": long_description,
210
+ "url": link,
211
+ }
212
+ if "huggingface.co" in link:
213
+ logger.warning(f"Filter out the link: {link}")
214
+ continue
215
+ responses.append(response)
216
+ else:
217
+ responses.append({"error": f"google search failed with response: {data}"})
218
+ except Exception as e:
219
+ logger.error(f"Google search failed with error: {e}")
220
+ responses.append({"error": f"google search failed with error: {e}"})
221
+
222
+ if len(responses) == 0:
223
+ responses.append(
224
+ "No relevant webpages found. Please simplify your query and expand the search space as much as you can, then try again.")
225
+ logger.debug(f"search result: {responses}")
226
+ responses.append(
227
+ "If the search result does not contain the information you want, please make reflection on your query: what went well, what didn't, then refine your search plan.")
228
+ return ActionResult(content=json.dumps(responses), keep=True, is_done=True), None
229
+
230
+
231
+ @ActionFactory.register(name=SearchAction.BAIDU.value.name,
232
+ desc=SearchAction.BAIDU.value.desc,
233
+ tool_name="search_api")
234
+ class SearchBaidu(ExecutableAction):
235
+ def __init__(self):
236
+ import_package("baidusearch")
237
+
238
+ def act(self, action: ActionModel, **kwargs) -> Tuple[ActionResult, Any]:
239
+ from baidusearch.baidusearch import search
240
+
241
+ query = action.params.get("query")
242
+ num_results = action.params.get("num_results", 6)
243
+ num_results = int(num_results)
244
+ logger.debug(f"Calling search_baidu with query: {query}")
245
+
246
+ responses = []
247
+ try:
248
+ responses = search(query, num_results=num_results)
249
+ except Exception as e:
250
+ logger.error(f"Baidu search failed with error: {e}")
251
+ responses.append({"error": f"baidu search failed with error: {e}"})
252
+
253
+ if len(responses) == 0:
254
+ responses.append(
255
+ "No relevant webpages found. Please simplify your query and expand the search space as much as you can, then try again.")
256
+ logger.debug(f"search result: {responses}")
257
+ responses.append(
258
+ "If the search result does not contain the information you want, please make reflection on your query: what went well, what didn't, then refine your search plan.")
259
+ return ActionResult(content=json.dumps(responses), keep=True, is_done=True), None
examples/tools/apis/search_api.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+ # Copyright (c) 2025 inclusionAI.
3
+
4
+ from aworld.core.tool.base import ToolFactory
5
+ from aworld.tools.template_tool import TemplateTool
6
+ from examples.tools.tool_action import SearchAction
7
+
8
+
9
+ @ToolFactory.register(name="search_api",
10
+ desc="search tool",
11
+ supported_action=SearchAction,
12
+ conf_file_name=f'search_api_tool.yaml')
13
+ class SearchTool(TemplateTool):
14
+ """Search Tool"""