camel-ai 0.2.3__py3-none-any.whl → 0.2.3a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of camel-ai might be problematic. Click here for more details.

Files changed (87) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +69 -93
  3. camel/agents/knowledge_graph_agent.py +6 -4
  4. camel/bots/__init__.py +2 -16
  5. camel/bots/discord_bot.py +206 -0
  6. camel/configs/__init__.py +2 -1
  7. camel/configs/anthropic_config.py +5 -2
  8. camel/configs/base_config.py +6 -6
  9. camel/configs/groq_config.py +3 -2
  10. camel/configs/ollama_config.py +2 -1
  11. camel/configs/openai_config.py +23 -2
  12. camel/configs/samba_config.py +2 -2
  13. camel/configs/togetherai_config.py +1 -1
  14. camel/configs/vllm_config.py +1 -1
  15. camel/configs/zhipuai_config.py +3 -2
  16. camel/embeddings/openai_embedding.py +2 -2
  17. camel/loaders/__init__.py +0 -2
  18. camel/loaders/firecrawl_reader.py +3 -3
  19. camel/loaders/unstructured_io.py +33 -35
  20. camel/messages/__init__.py +0 -1
  21. camel/models/__init__.py +4 -2
  22. camel/models/anthropic_model.py +26 -32
  23. camel/models/azure_openai_model.py +36 -39
  24. camel/models/base_model.py +20 -31
  25. camel/models/gemini_model.py +29 -37
  26. camel/models/groq_model.py +23 -29
  27. camel/models/litellm_model.py +61 -44
  28. camel/models/mistral_model.py +29 -32
  29. camel/models/model_factory.py +76 -66
  30. camel/models/nemotron_model.py +23 -33
  31. camel/models/ollama_model.py +47 -42
  32. camel/models/open_source_model.py +170 -0
  33. camel/models/{openai_compatible_model.py → openai_compatibility_model.py} +49 -31
  34. camel/models/openai_model.py +29 -48
  35. camel/models/reka_model.py +28 -30
  36. camel/models/samba_model.py +177 -82
  37. camel/models/stub_model.py +2 -2
  38. camel/models/togetherai_model.py +43 -37
  39. camel/models/vllm_model.py +50 -43
  40. camel/models/zhipuai_model.py +27 -33
  41. camel/retrievers/auto_retriever.py +10 -28
  42. camel/retrievers/vector_retriever.py +47 -58
  43. camel/societies/babyagi_playing.py +3 -6
  44. camel/societies/role_playing.py +3 -5
  45. camel/storages/graph_storages/graph_element.py +5 -3
  46. camel/storages/key_value_storages/json.py +1 -6
  47. camel/toolkits/__init__.py +7 -20
  48. camel/toolkits/base.py +3 -2
  49. camel/toolkits/code_execution.py +7 -6
  50. camel/toolkits/dalle_toolkit.py +6 -6
  51. camel/toolkits/github_toolkit.py +10 -9
  52. camel/toolkits/google_maps_toolkit.py +7 -7
  53. camel/toolkits/linkedin_toolkit.py +7 -7
  54. camel/toolkits/math_toolkit.py +8 -8
  55. camel/toolkits/open_api_toolkit.py +5 -5
  56. camel/toolkits/{function_tool.py → openai_function.py} +11 -34
  57. camel/toolkits/reddit_toolkit.py +7 -7
  58. camel/toolkits/retrieval_toolkit.py +5 -5
  59. camel/toolkits/search_toolkit.py +9 -9
  60. camel/toolkits/slack_toolkit.py +11 -11
  61. camel/toolkits/twitter_toolkit.py +452 -378
  62. camel/toolkits/weather_toolkit.py +6 -6
  63. camel/types/__init__.py +1 -6
  64. camel/types/enums.py +85 -40
  65. camel/types/openai_types.py +0 -3
  66. camel/utils/__init__.py +2 -0
  67. camel/utils/async_func.py +7 -7
  68. camel/utils/commons.py +3 -32
  69. camel/utils/token_counting.py +212 -30
  70. camel/workforce/role_playing_worker.py +1 -1
  71. camel/workforce/single_agent_worker.py +1 -1
  72. camel/workforce/task_channel.py +3 -4
  73. camel/workforce/workforce.py +4 -4
  74. {camel_ai-0.2.3.dist-info → camel_ai-0.2.3a0.dist-info}/METADATA +56 -27
  75. {camel_ai-0.2.3.dist-info → camel_ai-0.2.3a0.dist-info}/RECORD +76 -85
  76. {camel_ai-0.2.3.dist-info → camel_ai-0.2.3a0.dist-info}/WHEEL +1 -1
  77. camel/bots/discord_app.py +0 -138
  78. camel/bots/slack/__init__.py +0 -30
  79. camel/bots/slack/models.py +0 -158
  80. camel/bots/slack/slack_app.py +0 -255
  81. camel/loaders/chunkr_reader.py +0 -163
  82. camel/toolkits/arxiv_toolkit.py +0 -155
  83. camel/toolkits/ask_news_toolkit.py +0 -653
  84. camel/toolkits/google_scholar_toolkit.py +0 -146
  85. camel/toolkits/whatsapp_toolkit.py +0 -177
  86. camel/types/unified_model_type.py +0 -104
  87. camel_ai-0.2.3.dist-info/LICENSE +0 -201
@@ -1,255 +0,0 @@
1
- # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
2
- # Licensed under the Apache License, Version 2.0 (the “License”);
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an “AS IS” BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
14
- import logging
15
- import os
16
- from typing import TYPE_CHECKING, Any, Dict, Optional
17
-
18
- from slack_sdk.oauth.installation_store.async_installation_store import (
19
- AsyncInstallationStore,
20
- )
21
- from starlette import requests, responses
22
-
23
- from camel.bots.slack.models import (
24
- SlackAppMentionEventBody,
25
- SlackAppMentionEventProfile,
26
- SlackEventBody,
27
- SlackEventProfile,
28
- )
29
- from camel.utils import dependencies_required
30
-
31
- if TYPE_CHECKING:
32
- from slack_bolt.context.async_context import AsyncBoltContext
33
- from slack_bolt.context.say.async_say import AsyncSay
34
- from slack_sdk.web.async_client import AsyncWebClient
35
-
36
- logging.basicConfig(level=logging.INFO)
37
- logger = logging.getLogger(__name__)
38
-
39
-
40
- class SlackApp:
41
- r"""Represents a Slack app that is powered by a Slack Bolt `AsyncApp`.
42
-
43
- This class is responsible for initializing and managing the Slack
44
- application by setting up event handlers, running the app server, and
45
- handling events such as messages and mentions from Slack.
46
-
47
- Args:
48
- token (Optional[str]): Slack API token for authentication.
49
- scopes (Optional[str]): Slack app scopes for permissions.
50
- signing_secret (Optional[str]): Signing secret for verifying Slack
51
- requests.
52
- client_id (Optional[str]): Slack app client ID.
53
- client_secret (Optional[str]): Slack app client secret.
54
- redirect_uri_path (str): The URI path for OAuth redirect, defaults to
55
- "/slack/oauth_redirect".
56
- installation_store (Optional[AsyncInstallationStore]): The installation
57
- store for handling OAuth installations.
58
- """
59
-
60
- @dependencies_required('slack_bolt')
61
- def __init__(
62
- self,
63
- token: Optional[str] = None,
64
- scopes: Optional[str] = None,
65
- signing_secret: Optional[str] = None,
66
- client_id: Optional[str] = None,
67
- client_secret: Optional[str] = None,
68
- redirect_uri_path: str = "/slack/oauth_redirect",
69
- installation_store: Optional[AsyncInstallationStore] = None,
70
- ) -> None:
71
- r"""Initializes the SlackApp instance by setting up the Slack Bolt app
72
- and configuring event handlers and OAuth settings.
73
-
74
- Args:
75
- token (Optional[str]): The Slack API token.
76
- scopes (Optional[str]): The scopes for Slack app permissions.
77
- signing_secret (Optional[str]): The signing secret for verifying
78
- requests.
79
- client_id (Optional[str]): The Slack app client ID.
80
- client_secret (Optional[str]): The Slack app client secret.
81
- redirect_uri_path (str): The URI path for handling OAuth redirects
82
- (default is "/slack/oauth_redirect").
83
- installation_store (Optional[AsyncInstallationStore]): An optional
84
- installation store for OAuth installations.
85
- """
86
- from slack_bolt.adapter.starlette.async_handler import (
87
- AsyncSlackRequestHandler,
88
- )
89
- from slack_bolt.app.async_app import AsyncApp
90
- from slack_bolt.oauth.async_oauth_settings import AsyncOAuthSettings
91
-
92
- self.token: Optional[str] = token or os.getenv("SLACK_TOKEN")
93
- self.scopes: Optional[str] = scopes or os.getenv("SLACK_SCOPES")
94
- self.signing_secret: Optional[str] = signing_secret or os.getenv(
95
- "SLACK_SIGNING_SECRET"
96
- )
97
- self.client_id: Optional[str] = client_id or os.getenv(
98
- "SLACK_CLIENT_ID"
99
- )
100
- self.client_secret: Optional[str] = client_secret or os.getenv(
101
- "SLACK_CLIENT_SECRET"
102
- )
103
-
104
- if not all([self.token, self.scopes, self.signing_secret]):
105
- raise ValueError(
106
- "`SLACK_TOKEN`, `SLACK_SCOPES`, and `SLACK_SIGNING_SECRET` "
107
- "environment variables must be set. Get it here: "
108
- "`https://api.slack.com/apps`."
109
- )
110
-
111
- # Setup OAuth settings if client ID and secret are provided
112
- if self.client_id and self.client_secret:
113
- self._app = AsyncApp(
114
- oauth_settings=AsyncOAuthSettings(
115
- client_id=self.client_id,
116
- client_secret=self.client_secret,
117
- scopes=self.scopes,
118
- redirect_uri_path=redirect_uri_path,
119
- ),
120
- logger=logger,
121
- signing_secret=self.signing_secret,
122
- installation_store=installation_store,
123
- token=self.token,
124
- )
125
- else:
126
- # Initialize Slack Bolt AsyncApp with settings
127
- self._app = AsyncApp(
128
- logger=logger,
129
- signing_secret=self.signing_secret,
130
- installation_store=installation_store,
131
- token=self.token,
132
- )
133
-
134
- self._handler = AsyncSlackRequestHandler(self._app)
135
- self.setup_handlers()
136
-
137
- def setup_handlers(self) -> None:
138
- r"""Sets up the event handlers for Slack events, such as `app_mention`
139
- and `message`.
140
-
141
- This method registers the `app_mention` and `on_message` event handlers
142
- with the Slack Bolt app to respond to Slack events.
143
- """
144
- self._app.event("app_mention")(self.app_mention)
145
- self._app.event("message")(self.on_message)
146
-
147
- def run(
148
- self,
149
- port: int = 3000,
150
- path: str = "/slack/events",
151
- host: Optional[str] = None,
152
- ) -> None:
153
- r"""Starts the Slack Bolt app server to listen for incoming Slack
154
- events.
155
-
156
- Args:
157
- port (int): The port on which the server should run (default is
158
- 3000).
159
- path (str): The endpoint path for receiving Slack events (default
160
- is "/slack/events").
161
- host (Optional[str]): The hostname to bind the server (default is
162
- None).
163
- """
164
- self._app.start(port=port, path=path, host=host)
165
-
166
- async def handle_request(
167
- self, request: requests.Request
168
- ) -> responses.Response:
169
- r"""Handles incoming requests from Slack through the request handler.
170
-
171
- Args:
172
- request (Request): A Starlette request object representing the
173
- incoming request.
174
-
175
- Returns:
176
- The response generated by the Slack Bolt handler.
177
- """
178
- return await self._handler.handle(request)
179
-
180
- async def app_mention(
181
- self,
182
- context: "AsyncBoltContext",
183
- client: "AsyncWebClient",
184
- event: Dict[str, Any],
185
- body: Dict[str, Any],
186
- say: "AsyncSay",
187
- ) -> None:
188
- r"""Event handler for `app_mention` events.
189
-
190
- This method is triggered when someone mentions the app in Slack.
191
-
192
- Args:
193
- context (AsyncBoltContext): The Slack Bolt context for the event.
194
- client (AsyncWebClient): The Slack Web API client.
195
- event (Dict[str, Any]): The event data for the app mention.
196
- body (Dict[str, Any]): The full request body from Slack.
197
- say (AsyncSay): A function to send a response back to the channel.
198
- """
199
- event_profile = SlackAppMentionEventProfile(**event)
200
- event_body = SlackAppMentionEventBody(**body)
201
-
202
- logger.info(f"app_mention, context: {context}")
203
- logger.info(f"app_mention, client: {client}")
204
- logger.info(f"app_mention, event_profile: {event_profile}")
205
- logger.info(f"app_mention, event_body: {event_body}")
206
- logger.info(f"app_mention, say: {say}")
207
-
208
- async def on_message(
209
- self,
210
- context: "AsyncBoltContext",
211
- client: "AsyncWebClient",
212
- event: Dict[str, Any],
213
- body: Dict[str, Any],
214
- say: "AsyncSay",
215
- ) -> None:
216
- r"""Event handler for `message` events.
217
-
218
- This method is triggered when the app receives a message in Slack.
219
-
220
- Args:
221
- context (AsyncBoltContext): The Slack Bolt context for the event.
222
- client (AsyncWebClient): The Slack Web API client.
223
- event (Dict[str, Any]): The event data for the message.
224
- body (Dict[str, Any]): The full request body from Slack.
225
- say (AsyncSay): A function to send a response back to the channel.
226
- """
227
- await context.ack()
228
-
229
- event_profile = SlackEventProfile(**event)
230
- event_body = SlackEventBody(**body)
231
-
232
- logger.info(f"on_message, context: {context}")
233
- logger.info(f"on_message, client: {client}")
234
- logger.info(f"on_message, event_profile: {event_profile}")
235
- logger.info(f"on_message, event_body: {event_body}")
236
- logger.info(f"on_message, say: {say}")
237
-
238
- logger.info(f"Received message: {event_profile.text}")
239
-
240
- def mention_me(
241
- self, context: "AsyncBoltContext", body: SlackEventBody
242
- ) -> bool:
243
- r"""Check if the bot is mentioned in the message.
244
-
245
- Args:
246
- context (AsyncBoltContext): The Slack Bolt context for the event.
247
- body (SlackEventBody): The body of the Slack event.
248
-
249
- Returns:
250
- bool: True if the bot is mentioned in the message, False otherwise.
251
- """
252
- message = body.event.text
253
- bot_user_id = context.bot_user_id
254
- mention = f"<@{bot_user_id}>"
255
- return mention in message
@@ -1,163 +0,0 @@
1
- # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
2
- # Licensed under the Apache License, Version 2.0 (the “License”);
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an “AS IS” BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
14
-
15
- import json
16
- import logging
17
- import os
18
- import time
19
- from typing import IO, Any, Optional, Union
20
-
21
- import requests
22
-
23
- from camel.utils import api_keys_required
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
-
28
- class ChunkrReader:
29
- r"""Chunkr Reader for processing documents and returning content
30
- in various formats.
31
-
32
- Args:
33
- api_key (Optional[str], optional): The API key for Chunkr API. If not
34
- provided, it will be retrieved from the environment variable
35
- `CHUNKR_API_KEY`. (default: :obj:`None`)
36
- url (Optional[str], optional): The url to the Chunkr service.
37
- (default: :obj:`https://api.chunkr.ai/api/v1/task`)
38
- timeout (int, optional): The maximum time in seconds to wait for the
39
- API responses. (default: :obj:`30`)
40
- **kwargs (Any): Additional keyword arguments for request headers.
41
- """
42
-
43
- @api_keys_required("CHUNKR_API_KEY")
44
- def __init__(
45
- self,
46
- api_key: Optional[str] = None,
47
- url: Optional[str] = "https://api.chunkr.ai/api/v1/task",
48
- timeout: int = 30,
49
- **kwargs: Any,
50
- ) -> None:
51
- self._api_key = api_key or os.getenv('CHUNKR_API_KEY')
52
- self._url = os.getenv('CHUNKR_API_URL') or url
53
- self._headers = {
54
- "Authorization": f"{self._api_key}",
55
- **kwargs,
56
- }
57
- self.timeout = timeout
58
-
59
- def submit_task(
60
- self,
61
- file_path: str,
62
- model: str = "Fast",
63
- ocr_strategy: str = "Auto",
64
- target_chunk_length: str = "512",
65
- ) -> str:
66
- r"""Submits a file to the Chunkr API and returns the task ID.
67
-
68
- Args:
69
- file_path (str): The path to the file to be uploaded.
70
- model (str, optional): The model to be used for the task.
71
- (default: :obj:`Fast`)
72
- ocr_strategy (str, optional): The OCR strategy. Defaults to 'Auto'.
73
- target_chunk_length (str, optional): The target chunk length.
74
- (default: :obj:`512`)
75
-
76
- Returns:
77
- str: The task ID.
78
- """
79
- with open(file_path, 'rb') as file:
80
- files: dict[
81
- str, Union[tuple[None, IO[bytes]], tuple[None, str]]
82
- ] = {
83
- 'file': (
84
- None,
85
- file,
86
- ), # Properly pass the file as a binary stream
87
- 'model': (None, model),
88
- 'ocr_strategy': (None, ocr_strategy),
89
- 'target_chunk_length': (None, target_chunk_length),
90
- }
91
- try:
92
- response = requests.post(
93
- self._url, # type: ignore[arg-type]
94
- headers=self._headers,
95
- files=files,
96
- timeout=self.timeout,
97
- )
98
- response.raise_for_status()
99
- task_id = response.json().get('task_id')
100
- if not task_id:
101
- raise ValueError("Task ID not returned in the response.")
102
- logger.info(f"Task submitted successfully. Task ID: {task_id}")
103
- return task_id
104
- except Exception as e:
105
- logger.error(f"Failed to submit task: {e}")
106
- raise ValueError(f"Failed to submit task: {e}") from e
107
-
108
- def get_task_output(self, task_id: str, max_retries: int = 5) -> str:
109
- r"""Polls the Chunkr API to check the task status and returns the task
110
- result.
111
-
112
- Args:
113
- task_id (str): The task ID to check the status for.
114
- max_retries (int, optional): Maximum number of retry attempts.
115
- (default: :obj:`5`)
116
-
117
- Returns:
118
- str: The formatted task result in JSON format.
119
-
120
- Raises:
121
- ValueError: If the task status cannot be retrieved.
122
- RuntimeError: If the maximum number of retries is reached without
123
- a successful task completion.
124
- """
125
- url_get = f"{self._url}/{task_id}"
126
- attempts = 0
127
-
128
- while attempts < max_retries:
129
- try:
130
- response = requests.get(
131
- url_get, headers=self._headers, timeout=self.timeout
132
- )
133
- response.raise_for_status()
134
- task_status = response.json().get('status')
135
-
136
- if task_status == "Succeeded":
137
- logger.info(f"Task {task_id} completed successfully.")
138
- return self._pretty_print_response(response.json())
139
- else:
140
- logger.info(
141
- f"Task {task_id} is still {task_status}. Retrying "
142
- "in 5 seconds..."
143
- )
144
- except Exception as e:
145
- logger.error(f"Failed to retrieve task status: {e}")
146
- raise ValueError(f"Failed to retrieve task status: {e}") from e
147
-
148
- attempts += 1
149
- time.sleep(5)
150
-
151
- logger.error(f"Max retries reached for task {task_id}.")
152
- raise RuntimeError(f"Max retries reached for task {task_id}.")
153
-
154
- def _pretty_print_response(self, response_json: dict) -> str:
155
- r"""Pretty prints the JSON response.
156
-
157
- Args:
158
- response_json (dict): The response JSON to pretty print.
159
-
160
- Returns:
161
- str: Formatted JSON as a string.
162
- """
163
- return json.dumps(response_json, indent=4)
@@ -1,155 +0,0 @@
1
- # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
2
- # Licensed under the Apache License, Version 2.0 (the “License”);
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an “AS IS” BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
14
-
15
- from typing import Dict, Generator, List, Optional
16
-
17
- from camel.toolkits.base import BaseToolkit
18
- from camel.toolkits.function_tool import FunctionTool
19
- from camel.utils import dependencies_required
20
-
21
-
22
- class ArxivToolkit(BaseToolkit):
23
- r"""A toolkit for interacting with the arXiv API to search and download
24
- academic papers.
25
- """
26
-
27
- @dependencies_required('arxiv')
28
- def __init__(self) -> None:
29
- r"""Initializes the ArxivToolkit and sets up the arXiv client."""
30
- import arxiv
31
-
32
- self.client = arxiv.Client()
33
-
34
- def _get_search_results(
35
- self,
36
- query: str,
37
- paper_ids: Optional[List[str]] = None,
38
- max_results: Optional[int] = 5,
39
- ) -> Generator:
40
- r"""Retrieves search results from the arXiv API based on the provided
41
- query and optional paper IDs.
42
-
43
- Args:
44
- query (str): The search query string used to search for papers on
45
- arXiv.
46
- paper_ids (List[str], optional): A list of specific arXiv paper
47
- IDs to search for. (default::obj: `None`)
48
- max_results (int, optional): The maximum number of search results
49
- to retrieve. (default::obj: `5`)
50
-
51
- Returns:
52
- Generator: A generator that yields results from the arXiv search
53
- query, which includes metadata about each paper matching the
54
- query.
55
- """
56
- import arxiv
57
-
58
- paper_ids = paper_ids or []
59
- search_query = arxiv.Search(
60
- query=query,
61
- id_list=paper_ids,
62
- max_results=max_results,
63
- )
64
- return self.client.results(search_query)
65
-
66
- def search_papers(
67
- self,
68
- query: str,
69
- paper_ids: Optional[List[str]] = None,
70
- max_results: Optional[int] = 5,
71
- ) -> List[Dict[str, str]]:
72
- r"""Searches for academic papers on arXiv using a query string and
73
- optional paper IDs.
74
-
75
- Args:
76
- query (str): The search query string.
77
- paper_ids (List[str], optional): A list of specific arXiv paper
78
- IDs to search for. (default::obj: `None`)
79
- max_results (int, optional): The maximum number of search results
80
- to return. (default::obj: `5`)
81
-
82
- Returns:
83
- List[Dict[str, str]]: A list of dictionaries, each containing
84
- information about a paper, including title, published date,
85
- authors, entry ID, summary, and extracted text from the paper.
86
- """
87
- from arxiv2text import arxiv_to_text
88
-
89
- search_results = self._get_search_results(
90
- query, paper_ids, max_results
91
- )
92
- papers_data = []
93
-
94
- for paper in search_results:
95
- paper_info = {
96
- "title": paper.title,
97
- "published_date": paper.updated.date().isoformat(),
98
- "authors": [author.name for author in paper.authors],
99
- "entry_id": paper.entry_id,
100
- "summary": paper.summary,
101
- # TODO: Use chunkr instead of atxiv_to_text for better
102
- # performance
103
- "paper_text": arxiv_to_text(paper.pdf_url),
104
- }
105
- papers_data.append(paper_info)
106
-
107
- return papers_data
108
-
109
- def download_papers(
110
- self,
111
- query: str,
112
- paper_ids: Optional[List[str]] = None,
113
- max_results: Optional[int] = 5,
114
- output_dir: Optional[str] = "./",
115
- ) -> str:
116
- r"""Downloads PDFs of academic papers from arXiv based on the provided
117
- query.
118
-
119
- Args:
120
- query (str): The search query string.
121
- paper_ids (List[str], optional): A list of specific arXiv paper
122
- IDs to download. (default::obj: `None`)
123
- max_results (int, optional): The maximum number of search results
124
- to download. (default::obj: `5`)
125
- output_dir (str, optional): The directory to save the downloaded
126
- PDFs. Defaults to the current directory.
127
-
128
- Returns:
129
- str: Status message indicating success or failure.
130
- """
131
- try:
132
- search_results = self._get_search_results(
133
- query, paper_ids, max_results
134
- )
135
-
136
- for paper in search_results:
137
- paper.download_pdf(
138
- dirpath=output_dir, filename=f"{paper.title}" + ".pdf"
139
- )
140
- return "papers downloaded successfully"
141
- except Exception as e:
142
- return f"An error occurred: {e}"
143
-
144
- def get_tools(self) -> List[FunctionTool]:
145
- r"""Returns a list of FunctionTool objects representing the
146
- functions in the toolkit.
147
-
148
- Returns:
149
- List[FunctionTool]: A list of FunctionTool objects
150
- representing the functions in the toolkit.
151
- """
152
- return [
153
- FunctionTool(self.search_papers),
154
- FunctionTool(self.download_papers),
155
- ]