camel-ai 0.2.11__py3-none-any.whl → 0.2.13__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.
- camel/__init__.py +1 -1
- camel/agents/chat_agent.py +14 -2
- camel/benchmarks/__init__.py +18 -0
- camel/benchmarks/base.py +152 -0
- camel/benchmarks/gaia.py +478 -0
- camel/configs/__init__.py +3 -0
- camel/configs/ollama_config.py +4 -2
- camel/configs/sglang_config.py +71 -0
- camel/data_collector/__init__.py +19 -0
- camel/data_collector/alpaca_collector.py +127 -0
- camel/data_collector/base.py +211 -0
- camel/data_collector/sharegpt_collector.py +205 -0
- camel/datahubs/__init__.py +23 -0
- camel/datahubs/base.py +136 -0
- camel/datahubs/huggingface.py +433 -0
- camel/datahubs/models.py +22 -0
- camel/embeddings/openai_compatible_embedding.py +1 -1
- camel/embeddings/openai_embedding.py +1 -1
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/e2b_interpreter.py +136 -0
- camel/loaders/__init__.py +3 -1
- camel/loaders/base_io.py +41 -41
- camel/messages/__init__.py +2 -0
- camel/messages/base.py +5 -5
- camel/models/__init__.py +4 -0
- camel/models/anthropic_model.py +15 -5
- camel/models/azure_openai_model.py +1 -1
- camel/models/base_model.py +28 -0
- camel/models/deepseek_model.py +1 -1
- camel/models/fish_audio_model.py +146 -0
- camel/models/gemini_model.py +1 -1
- camel/models/groq_model.py +2 -2
- camel/models/model_factory.py +3 -0
- camel/models/nemotron_model.py +1 -1
- camel/models/nvidia_model.py +1 -1
- camel/models/ollama_model.py +13 -1
- camel/models/openai_compatible_model.py +1 -1
- camel/models/openai_model.py +1 -27
- camel/models/qwen_model.py +1 -1
- camel/models/reward/__init__.py +22 -0
- camel/models/reward/base_reward_model.py +58 -0
- camel/models/reward/evaluator.py +63 -0
- camel/models/reward/nemotron_model.py +112 -0
- camel/models/samba_model.py +1 -1
- camel/models/sglang_model.py +225 -0
- camel/models/togetherai_model.py +1 -1
- camel/models/vllm_model.py +2 -2
- camel/models/yi_model.py +1 -1
- camel/models/zhipuai_model.py +1 -1
- camel/personas/persona_hub.py +2 -2
- camel/runtime/configs.py +12 -12
- camel/runtime/docker_runtime.py +7 -7
- camel/runtime/llm_guard_runtime.py +3 -3
- camel/runtime/remote_http_runtime.py +5 -5
- camel/runtime/utils/function_risk_toolkit.py +1 -1
- camel/runtime/utils/ignore_risk_toolkit.py +2 -2
- camel/schemas/openai_converter.py +2 -2
- camel/societies/workforce/role_playing_worker.py +2 -2
- camel/societies/workforce/single_agent_worker.py +2 -2
- camel/societies/workforce/workforce.py +3 -3
- camel/storages/object_storages/amazon_s3.py +2 -2
- camel/storages/object_storages/azure_blob.py +2 -2
- camel/storages/object_storages/google_cloud.py +2 -2
- camel/toolkits/__init__.py +2 -0
- camel/toolkits/arxiv_toolkit.py +6 -6
- camel/toolkits/ask_news_toolkit.py +2 -2
- camel/toolkits/code_execution.py +5 -1
- camel/toolkits/function_tool.py +41 -0
- camel/toolkits/github_toolkit.py +3 -3
- camel/toolkits/google_scholar_toolkit.py +16 -2
- camel/toolkits/math_toolkit.py +47 -16
- camel/toolkits/meshy_toolkit.py +2 -2
- camel/toolkits/search_toolkit.py +155 -3
- camel/toolkits/stripe_toolkit.py +273 -0
- camel/types/__init__.py +2 -0
- camel/types/enums.py +27 -2
- camel/utils/token_counting.py +31 -12
- {camel_ai-0.2.11.dist-info → camel_ai-0.2.13.dist-info}/METADATA +24 -14
- {camel_ai-0.2.11.dist-info → camel_ai-0.2.13.dist-info}/RECORD +81 -61
- {camel_ai-0.2.11.dist-info → camel_ai-0.2.13.dist-info}/LICENSE +0 -0
- {camel_ai-0.2.11.dist-info → camel_ai-0.2.13.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
# ========= Copyright 2023-2024 @ 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-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
import tempfile
|
|
17
|
+
from typing import Any, List, Optional
|
|
18
|
+
|
|
19
|
+
from camel.datahubs.base import BaseDatasetManager
|
|
20
|
+
from camel.datahubs.models import Record
|
|
21
|
+
from camel.logger import get_logger
|
|
22
|
+
from camel.types import HuggingFaceRepoType
|
|
23
|
+
from camel.utils import api_keys_required, dependencies_required
|
|
24
|
+
|
|
25
|
+
logger = get_logger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class HuggingFaceDatasetManager(BaseDatasetManager):
|
|
29
|
+
r"""A dataset manager for Hugging Face datasets. This class provides
|
|
30
|
+
methods to create, add, update, delete, and list records in a dataset on
|
|
31
|
+
the Hugging Face Hub.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
token (str): The Hugging Face API token. If not provided, the token
|
|
35
|
+
will be read from the environment variable `HUGGING_FACE_TOKEN`.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@api_keys_required("HUGGING_FACE_TOKEN")
|
|
39
|
+
@dependencies_required('huggingface_hub')
|
|
40
|
+
def __init__(self, token: Optional[str] = None):
|
|
41
|
+
from huggingface_hub import HfApi
|
|
42
|
+
|
|
43
|
+
self._api_key = token or os.getenv("HUGGING_FACE_TOKEN")
|
|
44
|
+
self.api = HfApi(token=self._api_key)
|
|
45
|
+
|
|
46
|
+
def create_dataset_card(
|
|
47
|
+
self,
|
|
48
|
+
dataset_name: str,
|
|
49
|
+
description: str,
|
|
50
|
+
license: Optional[str] = None,
|
|
51
|
+
version: Optional[str] = None,
|
|
52
|
+
tags: Optional[List[str]] = None,
|
|
53
|
+
authors: Optional[List[str]] = None,
|
|
54
|
+
size_category: Optional[List[str]] = None,
|
|
55
|
+
language: Optional[List[str]] = None,
|
|
56
|
+
task_categories: Optional[List[str]] = None,
|
|
57
|
+
content: Optional[str] = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
r"""Creates and uploads a dataset card to the Hugging Face Hub in YAML
|
|
60
|
+
format.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
dataset_name (str): The name of the dataset.
|
|
64
|
+
description (str): A description of the dataset.
|
|
65
|
+
license (str): The license of the dataset. (default: :obj:`None`)
|
|
66
|
+
version (str): The version of the dataset. (default: :obj:`None`)
|
|
67
|
+
tags (list): A list of tags for the dataset.(default: :obj:`None`)
|
|
68
|
+
authors (list): A list of authors of the dataset. (default:
|
|
69
|
+
:obj:`None`)
|
|
70
|
+
size_category (list): A size category for the dataset. (default:
|
|
71
|
+
:obj:`None`)
|
|
72
|
+
language (list): A list of languages the dataset is in. (default:
|
|
73
|
+
:obj:`None`)
|
|
74
|
+
task_categories (list): A list of task categories. (default:
|
|
75
|
+
:obj:`None`)
|
|
76
|
+
content (str): Custom markdown content that the user wants to add
|
|
77
|
+
to the dataset card. (default: :obj:`None`)
|
|
78
|
+
"""
|
|
79
|
+
import yaml
|
|
80
|
+
|
|
81
|
+
metadata = {
|
|
82
|
+
"license": license,
|
|
83
|
+
"authors": authors,
|
|
84
|
+
"task_categories": task_categories,
|
|
85
|
+
"language": language,
|
|
86
|
+
"tags": tags,
|
|
87
|
+
"pretty_name": dataset_name,
|
|
88
|
+
"size_categories": size_category,
|
|
89
|
+
"version": version,
|
|
90
|
+
"description": description,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Remove keys with None values
|
|
94
|
+
metadata = {k: v for k, v in metadata.items() if v}
|
|
95
|
+
|
|
96
|
+
card_content = (
|
|
97
|
+
"---\n"
|
|
98
|
+
+ yaml.dump(metadata, default_flow_style=False, allow_unicode=True)
|
|
99
|
+
+ "\n---"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if content:
|
|
103
|
+
card_content += f"\n\n# Additional Information\n{content}\n"
|
|
104
|
+
|
|
105
|
+
self._upload_file(
|
|
106
|
+
file_content=card_content,
|
|
107
|
+
dataset_name=dataset_name,
|
|
108
|
+
filepath="README.md",
|
|
109
|
+
file_type="md",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def create_dataset(
|
|
113
|
+
self, name: str, private: bool = False, **kwargs: Any
|
|
114
|
+
) -> str:
|
|
115
|
+
r"""Creates a new dataset on the Hugging Face Hub.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
name (str): The name of the dataset.
|
|
119
|
+
private (bool): Whether the dataset should be private. defaults to
|
|
120
|
+
False.
|
|
121
|
+
kwargs (Any): Additional keyword arguments.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
str: The URL of the created dataset.
|
|
125
|
+
"""
|
|
126
|
+
from huggingface_hub.errors import RepositoryNotFoundError
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
self.api.repo_info(
|
|
130
|
+
repo_id=name,
|
|
131
|
+
repo_type=HuggingFaceRepoType.DATASET.value,
|
|
132
|
+
**kwargs,
|
|
133
|
+
)
|
|
134
|
+
except RepositoryNotFoundError:
|
|
135
|
+
self.api.create_repo(
|
|
136
|
+
repo_id=name,
|
|
137
|
+
repo_type=HuggingFaceRepoType.DATASET.value,
|
|
138
|
+
private=private,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return f"https://huggingface.co/datasets/{name}"
|
|
142
|
+
|
|
143
|
+
def list_datasets(
|
|
144
|
+
self, username: str, limit: int = 100, **kwargs: Any
|
|
145
|
+
) -> List[str]:
|
|
146
|
+
r"""Lists all datasets for the current user.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
username (str): The username of the user whose datasets to list.
|
|
150
|
+
limit (int): The maximum number of datasets to list.
|
|
151
|
+
(default: :obj:`100`)
|
|
152
|
+
kwargs (Any): Additional keyword arguments.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
List[str]: A list of dataset ids.
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
return [
|
|
159
|
+
dataset.id
|
|
160
|
+
for dataset in self.api.list_datasets(
|
|
161
|
+
author=username, limit=limit, **kwargs
|
|
162
|
+
)
|
|
163
|
+
]
|
|
164
|
+
except Exception as e:
|
|
165
|
+
logger.error(f"Error listing datasets: {e}")
|
|
166
|
+
return []
|
|
167
|
+
|
|
168
|
+
def delete_dataset(self, dataset_name: str, **kwargs: Any) -> None:
|
|
169
|
+
r"""Deletes a dataset from the Hugging Face Hub.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
dataset_name (str): The name of the dataset to delete.
|
|
173
|
+
kwargs (Any): Additional keyword arguments.
|
|
174
|
+
"""
|
|
175
|
+
try:
|
|
176
|
+
self.api.delete_repo(
|
|
177
|
+
repo_id=dataset_name,
|
|
178
|
+
repo_type=HuggingFaceRepoType.DATASET.value,
|
|
179
|
+
**kwargs,
|
|
180
|
+
)
|
|
181
|
+
logger.info(f"Dataset '{dataset_name}' deleted successfully.")
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logger.error(f"Error deleting dataset '{dataset_name}': {e}")
|
|
184
|
+
raise
|
|
185
|
+
|
|
186
|
+
def add_records(
|
|
187
|
+
self,
|
|
188
|
+
dataset_name: str,
|
|
189
|
+
records: List[Record],
|
|
190
|
+
filepath: str = "records/records.json",
|
|
191
|
+
**kwargs: Any,
|
|
192
|
+
) -> None:
|
|
193
|
+
r"""Adds records to a dataset on the Hugging Face Hub.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
dataset_name (str): The name of the dataset.
|
|
197
|
+
records (List[Record]): A list of records to add to the dataset.
|
|
198
|
+
filepath (str): The path to the file containing the records.
|
|
199
|
+
kwargs (Any): Additional keyword arguments.
|
|
200
|
+
|
|
201
|
+
Raises:
|
|
202
|
+
ValueError: If the dataset already has a records file.
|
|
203
|
+
"""
|
|
204
|
+
existing_records = self._download_records(
|
|
205
|
+
dataset_name=dataset_name, filepath=filepath, **kwargs
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if existing_records:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
f"Dataset '{filepath}' already exists. "
|
|
211
|
+
f"Use `update_records` to modify."
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
self._upload_records(
|
|
215
|
+
records=records,
|
|
216
|
+
dataset_name=dataset_name,
|
|
217
|
+
filepath=filepath,
|
|
218
|
+
**kwargs,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
def update_records(
|
|
222
|
+
self,
|
|
223
|
+
dataset_name: str,
|
|
224
|
+
records: List[Record],
|
|
225
|
+
filepath: str = "records/records.json",
|
|
226
|
+
**kwargs: Any,
|
|
227
|
+
) -> None:
|
|
228
|
+
r"""Updates records in a dataset on the Hugging Face Hub.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
dataset_name (str): The name of the dataset.
|
|
232
|
+
records (List[Record]): A list of records to update in the dataset.
|
|
233
|
+
filepath (str): The path to the file containing the records.
|
|
234
|
+
kwargs (Any): Additional keyword arguments.
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
ValueError: If the dataset does not have an existing file to update
|
|
238
|
+
records in.
|
|
239
|
+
"""
|
|
240
|
+
existing_records = self._download_records(
|
|
241
|
+
dataset_name=dataset_name, filepath=filepath, **kwargs
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
if not existing_records:
|
|
245
|
+
logger.warning(
|
|
246
|
+
f"Dataset '{dataset_name}' does not have existing "
|
|
247
|
+
"records. Adding new records."
|
|
248
|
+
)
|
|
249
|
+
self._upload_records(
|
|
250
|
+
records=records,
|
|
251
|
+
dataset_name=dataset_name,
|
|
252
|
+
filepath=filepath,
|
|
253
|
+
**kwargs,
|
|
254
|
+
)
|
|
255
|
+
return
|
|
256
|
+
|
|
257
|
+
old_dict = {record.id: record for record in existing_records}
|
|
258
|
+
new_dict = {record.id: record for record in records}
|
|
259
|
+
merged_dict = old_dict.copy()
|
|
260
|
+
merged_dict.update(new_dict)
|
|
261
|
+
|
|
262
|
+
self._upload_records(
|
|
263
|
+
records=list(merged_dict.values()),
|
|
264
|
+
dataset_name=dataset_name,
|
|
265
|
+
filepath=filepath,
|
|
266
|
+
**kwargs,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def delete_record(
|
|
270
|
+
self,
|
|
271
|
+
dataset_name: str,
|
|
272
|
+
record_id: str,
|
|
273
|
+
filepath: str = "records/records.json",
|
|
274
|
+
**kwargs: Any,
|
|
275
|
+
) -> None:
|
|
276
|
+
r"""Deletes a record from the dataset.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
dataset_name (str): The name of the dataset.
|
|
280
|
+
record_id (str): The ID of the record to delete.
|
|
281
|
+
filepath (str): The path to the file containing the records.
|
|
282
|
+
kwargs (Any): Additional keyword arguments.
|
|
283
|
+
|
|
284
|
+
Raises:
|
|
285
|
+
ValueError: If the dataset does not have an existing file to delete
|
|
286
|
+
records from.
|
|
287
|
+
"""
|
|
288
|
+
existing_records = self._download_records(
|
|
289
|
+
dataset_name=dataset_name, filepath=filepath, **kwargs
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
if not existing_records:
|
|
293
|
+
raise ValueError(
|
|
294
|
+
f"Dataset '{dataset_name}' does not have an existing file to "
|
|
295
|
+
f"delete records from."
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
filtered_records = [
|
|
299
|
+
record for record in existing_records if record.id != record_id
|
|
300
|
+
]
|
|
301
|
+
|
|
302
|
+
self._upload_records(
|
|
303
|
+
records=filtered_records,
|
|
304
|
+
dataset_name=dataset_name,
|
|
305
|
+
filepath=filepath,
|
|
306
|
+
**kwargs,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
def list_records(
|
|
310
|
+
self,
|
|
311
|
+
dataset_name: str,
|
|
312
|
+
filepath: str = "records/records.json",
|
|
313
|
+
**kwargs: Any,
|
|
314
|
+
) -> List[Record]:
|
|
315
|
+
r"""Lists all records in a dataset.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
dataset_name (str): The name of the dataset.
|
|
319
|
+
filepath (str): The path to the file containing the records.
|
|
320
|
+
kwargs (Any): Additional keyword arguments.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
List[Record]: A list of records in the dataset.
|
|
324
|
+
"""
|
|
325
|
+
return self._download_records(
|
|
326
|
+
dataset_name=dataset_name, filepath=filepath, **kwargs
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
def _download_records(
|
|
330
|
+
self, dataset_name: str, filepath: str, **kwargs: Any
|
|
331
|
+
) -> List[Record]:
|
|
332
|
+
from huggingface_hub import hf_hub_download
|
|
333
|
+
from huggingface_hub.errors import EntryNotFoundError
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
downloaded_file_path = hf_hub_download(
|
|
337
|
+
repo_id=dataset_name,
|
|
338
|
+
filename=filepath,
|
|
339
|
+
repo_type=HuggingFaceRepoType.DATASET.value,
|
|
340
|
+
token=self._api_key,
|
|
341
|
+
**kwargs,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
with open(downloaded_file_path, "r") as f:
|
|
345
|
+
records_data = json.load(f)
|
|
346
|
+
|
|
347
|
+
return [Record(**record) for record in records_data]
|
|
348
|
+
except EntryNotFoundError:
|
|
349
|
+
logger.info(f"No records found for dataset '{dataset_name}'.")
|
|
350
|
+
return []
|
|
351
|
+
except Exception as e:
|
|
352
|
+
logger.error(f"Error downloading or processing records: {e}")
|
|
353
|
+
raise e
|
|
354
|
+
|
|
355
|
+
def _upload_records(
|
|
356
|
+
self,
|
|
357
|
+
records: List[Record],
|
|
358
|
+
dataset_name: str,
|
|
359
|
+
filepath: str,
|
|
360
|
+
**kwargs: Any,
|
|
361
|
+
):
|
|
362
|
+
with tempfile.NamedTemporaryFile(
|
|
363
|
+
delete=False, mode="w", newline="", encoding="utf-8"
|
|
364
|
+
) as f:
|
|
365
|
+
json.dump([record.model_dump() for record in records], f)
|
|
366
|
+
temp_file_path = f.name
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
self.api.upload_file(
|
|
370
|
+
path_or_fileobj=temp_file_path,
|
|
371
|
+
path_in_repo=filepath,
|
|
372
|
+
repo_id=dataset_name,
|
|
373
|
+
repo_type=HuggingFaceRepoType.DATASET.value,
|
|
374
|
+
**kwargs,
|
|
375
|
+
)
|
|
376
|
+
except Exception as e:
|
|
377
|
+
logger.error(f"Error uploading records file: {e}")
|
|
378
|
+
raise
|
|
379
|
+
finally:
|
|
380
|
+
if os.path.exists(temp_file_path):
|
|
381
|
+
os.remove(temp_file_path)
|
|
382
|
+
|
|
383
|
+
def _upload_file(
|
|
384
|
+
self,
|
|
385
|
+
file_content: str,
|
|
386
|
+
dataset_name: str,
|
|
387
|
+
filepath: str,
|
|
388
|
+
file_type: str = "json",
|
|
389
|
+
**kwargs: Any,
|
|
390
|
+
):
|
|
391
|
+
with tempfile.NamedTemporaryFile(
|
|
392
|
+
mode="w", delete=False, suffix=f".{file_type}"
|
|
393
|
+
) as f:
|
|
394
|
+
if file_type == "json":
|
|
395
|
+
if isinstance(file_content, str):
|
|
396
|
+
try:
|
|
397
|
+
json_content = json.loads(file_content)
|
|
398
|
+
except json.JSONDecodeError:
|
|
399
|
+
raise ValueError(
|
|
400
|
+
"Invalid JSON string provided for file_content."
|
|
401
|
+
)
|
|
402
|
+
else:
|
|
403
|
+
try:
|
|
404
|
+
json.dumps(file_content)
|
|
405
|
+
json_content = file_content
|
|
406
|
+
except (TypeError, ValueError):
|
|
407
|
+
raise ValueError(
|
|
408
|
+
"file_content is not JSON serializable."
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
json.dump(json_content, f)
|
|
412
|
+
elif file_type == "md" or file_type == "txt":
|
|
413
|
+
f.write(file_content)
|
|
414
|
+
else:
|
|
415
|
+
raise ValueError(f"Unsupported file type: {file_type}")
|
|
416
|
+
|
|
417
|
+
temp_file_path = f.name
|
|
418
|
+
|
|
419
|
+
try:
|
|
420
|
+
self.api.upload_file(
|
|
421
|
+
path_or_fileobj=temp_file_path,
|
|
422
|
+
path_in_repo=filepath,
|
|
423
|
+
repo_id=dataset_name,
|
|
424
|
+
repo_type=HuggingFaceRepoType.DATASET.value,
|
|
425
|
+
**kwargs,
|
|
426
|
+
)
|
|
427
|
+
logger.info(f"File uploaded successfully: {filepath}")
|
|
428
|
+
except Exception as e:
|
|
429
|
+
logger.error(f"Error uploading file: {e}")
|
|
430
|
+
raise
|
|
431
|
+
|
|
432
|
+
if os.path.exists(temp_file_path):
|
|
433
|
+
os.remove(temp_file_path)
|
camel/datahubs/models.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ========= Copyright 2023-2024 @ 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-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
from typing import Any, Dict, Optional
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Record(BaseModel):
|
|
20
|
+
id: Optional[str] = None
|
|
21
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
22
|
+
content: Dict[str, Any]
|
|
@@ -56,7 +56,7 @@ class OpenAIEmbedding(BaseEmbedding[str]):
|
|
|
56
56
|
assert isinstance(dimensions, int)
|
|
57
57
|
self.output_dim = dimensions
|
|
58
58
|
self._api_key = api_key or os.environ.get("OPENAI_API_KEY")
|
|
59
|
-
self.client = OpenAI(timeout=
|
|
59
|
+
self.client = OpenAI(timeout=180, max_retries=3, api_key=self._api_key)
|
|
60
60
|
|
|
61
61
|
@api_keys_required("OPENAI_API_KEY")
|
|
62
62
|
def embed_list(
|
camel/interpreters/__init__.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
from .base import BaseInterpreter
|
|
16
16
|
from .docker_interpreter import DockerInterpreter
|
|
17
|
+
from .e2b_interpreter import E2BInterpreter
|
|
17
18
|
from .internal_python_interpreter import InternalPythonInterpreter
|
|
18
19
|
from .interpreter_error import InterpreterError
|
|
19
20
|
from .ipython_interpreter import JupyterKernelInterpreter
|
|
@@ -26,4 +27,5 @@ __all__ = [
|
|
|
26
27
|
'SubprocessInterpreter',
|
|
27
28
|
'DockerInterpreter',
|
|
28
29
|
'JupyterKernelInterpreter',
|
|
30
|
+
'E2BInterpreter',
|
|
29
31
|
]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# ========= Copyright 2023-2024 @ 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-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
import os
|
|
15
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
from camel.interpreters.base import BaseInterpreter
|
|
18
|
+
from camel.interpreters.interpreter_error import InterpreterError
|
|
19
|
+
from camel.logger import get_logger
|
|
20
|
+
from camel.utils import api_keys_required
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class E2BInterpreter(BaseInterpreter):
|
|
26
|
+
r"""E2B Code Interpreter implementation.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
require_confirm (bool, optional): If True, prompt user before running
|
|
30
|
+
code strings for security. (default: :obj:`True`)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
_CODE_TYPE_MAPPING: ClassVar[Dict[str, Optional[str]]] = {
|
|
34
|
+
"python": None,
|
|
35
|
+
"py3": None,
|
|
36
|
+
"python3": None,
|
|
37
|
+
"py": None,
|
|
38
|
+
"shell": "bash",
|
|
39
|
+
"bash": "bash",
|
|
40
|
+
"sh": "bash",
|
|
41
|
+
"java": "java",
|
|
42
|
+
"javascript": "js",
|
|
43
|
+
"r": "r",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@api_keys_required("E2B_API_KEY")
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
require_confirm: bool = True,
|
|
50
|
+
) -> None:
|
|
51
|
+
from e2b_code_interpreter import Sandbox
|
|
52
|
+
|
|
53
|
+
self.require_confirm = require_confirm
|
|
54
|
+
self._sandbox = Sandbox(api_key=os.environ.get("E2B_API_KEY"))
|
|
55
|
+
|
|
56
|
+
def __del__(self) -> None:
|
|
57
|
+
r"""Destructor for the E2BInterpreter class.
|
|
58
|
+
|
|
59
|
+
This method ensures that the e2b sandbox is killed when the
|
|
60
|
+
interpreter is deleted.
|
|
61
|
+
"""
|
|
62
|
+
if (
|
|
63
|
+
hasattr(self, '_sandbox')
|
|
64
|
+
and self._sandbox is not None
|
|
65
|
+
and self._sandbox.is_running()
|
|
66
|
+
):
|
|
67
|
+
self._sandbox.kill()
|
|
68
|
+
|
|
69
|
+
def run(
|
|
70
|
+
self,
|
|
71
|
+
code: str,
|
|
72
|
+
code_type: str,
|
|
73
|
+
) -> str:
|
|
74
|
+
r"""Executes the given code in the e2b sandbox.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
code (str): The code string to execute.
|
|
78
|
+
code_type (str): The type of code to execute (e.g., 'python',
|
|
79
|
+
'bash').
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
str: The string representation of the output of the executed code.
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
InterpreterError: If the `code_type` is not supported or if any
|
|
86
|
+
runtime error occurs during the execution of the code.
|
|
87
|
+
"""
|
|
88
|
+
if code_type not in self._CODE_TYPE_MAPPING:
|
|
89
|
+
raise InterpreterError(
|
|
90
|
+
f"Unsupported code type {code_type}. "
|
|
91
|
+
f"`{self.__class__.__name__}` only supports "
|
|
92
|
+
f"{', '.join(list(self._CODE_TYPE_MAPPING.keys()))}."
|
|
93
|
+
)
|
|
94
|
+
# Print code for security checking
|
|
95
|
+
if self.require_confirm:
|
|
96
|
+
logger.info(
|
|
97
|
+
f"The following {code_type} code will run on your "
|
|
98
|
+
"e2b sandbox: {code}"
|
|
99
|
+
)
|
|
100
|
+
while True:
|
|
101
|
+
choice = input("Running code? [Y/n]:").lower()
|
|
102
|
+
if choice in ["y", "yes", "ye"]:
|
|
103
|
+
break
|
|
104
|
+
elif choice not in ["no", "n"]:
|
|
105
|
+
continue
|
|
106
|
+
raise InterpreterError(
|
|
107
|
+
"Execution halted: User opted not to run the code. "
|
|
108
|
+
"This choice stops the current operation and any "
|
|
109
|
+
"further code execution."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if self._CODE_TYPE_MAPPING[code_type] is None:
|
|
113
|
+
execution = self._sandbox.run_code(code)
|
|
114
|
+
else:
|
|
115
|
+
execution = self._sandbox.run_code(
|
|
116
|
+
code=code, language=self._CODE_TYPE_MAPPING[code_type]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if execution.text and execution.text.lower() != "none":
|
|
120
|
+
return execution.text
|
|
121
|
+
|
|
122
|
+
if execution.logs:
|
|
123
|
+
if execution.logs.stdout:
|
|
124
|
+
return ",".join(execution.logs.stdout)
|
|
125
|
+
elif execution.logs.stderr:
|
|
126
|
+
return ",".join(execution.logs.stderr)
|
|
127
|
+
|
|
128
|
+
return str(execution.error)
|
|
129
|
+
|
|
130
|
+
def supported_code_types(self) -> List[str]:
|
|
131
|
+
r"""Provides supported code types by the interpreter."""
|
|
132
|
+
return list(self._CODE_TYPE_MAPPING.keys())
|
|
133
|
+
|
|
134
|
+
def update_action_space(self, action_space: Dict[str, Any]) -> None:
|
|
135
|
+
r"""Updates action space for *python* interpreter"""
|
|
136
|
+
raise RuntimeError("E2B doesn't support " "`action_space`.")
|
camel/loaders/__init__.py
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
15
|
from .apify_reader import Apify
|
|
16
|
-
from .base_io import File
|
|
16
|
+
from .base_io import File, create_file, create_file_from_raw_bytes
|
|
17
17
|
from .chunkr_reader import ChunkrReader
|
|
18
18
|
from .firecrawl_reader import Firecrawl
|
|
19
19
|
from .jina_url_reader import JinaURLReader
|
|
@@ -21,6 +21,8 @@ from .unstructured_io import UnstructuredIO
|
|
|
21
21
|
|
|
22
22
|
__all__ = [
|
|
23
23
|
'File',
|
|
24
|
+
'create_file',
|
|
25
|
+
'create_file_from_raw_bytes',
|
|
24
26
|
'UnstructuredIO',
|
|
25
27
|
'JinaURLReader',
|
|
26
28
|
'Firecrawl',
|