camel-ai 0.2.21__py3-none-any.whl → 0.2.23__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/_types.py +41 -0
- camel/agents/_utils.py +188 -0
- camel/agents/chat_agent.py +570 -965
- camel/agents/knowledge_graph_agent.py +7 -1
- camel/agents/multi_hop_generator_agent.py +1 -1
- camel/configs/base_config.py +10 -13
- camel/configs/deepseek_config.py +4 -30
- camel/configs/gemini_config.py +5 -31
- camel/configs/openai_config.py +14 -32
- camel/configs/qwen_config.py +36 -36
- camel/datagen/self_improving_cot.py +81 -3
- camel/datagen/self_instruct/filter/instruction_filter.py +19 -3
- camel/datagen/self_instruct/self_instruct.py +53 -4
- camel/datasets/__init__.py +28 -0
- camel/datasets/base.py +969 -0
- camel/embeddings/openai_embedding.py +10 -1
- camel/environments/__init__.py +16 -0
- camel/environments/base.py +503 -0
- camel/extractors/__init__.py +16 -0
- camel/extractors/base.py +263 -0
- camel/interpreters/docker/Dockerfile +12 -0
- camel/interpreters/docker_interpreter.py +19 -1
- camel/interpreters/subprocess_interpreter.py +42 -17
- camel/loaders/__init__.py +2 -0
- camel/loaders/mineru_extractor.py +250 -0
- camel/memories/agent_memories.py +16 -1
- camel/memories/blocks/chat_history_block.py +10 -2
- camel/memories/blocks/vectordb_block.py +1 -0
- camel/memories/context_creators/score_based.py +20 -3
- camel/memories/records.py +10 -0
- camel/messages/base.py +8 -8
- camel/models/__init__.py +2 -0
- camel/models/_utils.py +57 -0
- camel/models/aiml_model.py +48 -17
- camel/models/anthropic_model.py +41 -3
- camel/models/azure_openai_model.py +39 -3
- camel/models/base_audio_model.py +92 -0
- camel/models/base_model.py +132 -4
- camel/models/cohere_model.py +88 -11
- camel/models/deepseek_model.py +107 -63
- camel/models/fish_audio_model.py +18 -8
- camel/models/gemini_model.py +133 -15
- camel/models/groq_model.py +72 -10
- camel/models/internlm_model.py +14 -3
- camel/models/litellm_model.py +9 -2
- camel/models/mistral_model.py +42 -5
- camel/models/model_manager.py +57 -3
- camel/models/moonshot_model.py +33 -4
- camel/models/nemotron_model.py +32 -3
- camel/models/nvidia_model.py +43 -3
- camel/models/ollama_model.py +139 -17
- camel/models/openai_audio_models.py +87 -2
- camel/models/openai_compatible_model.py +37 -3
- camel/models/openai_model.py +158 -46
- camel/models/qwen_model.py +61 -4
- camel/models/reka_model.py +53 -3
- camel/models/samba_model.py +209 -4
- camel/models/sglang_model.py +153 -14
- camel/models/siliconflow_model.py +16 -3
- camel/models/stub_model.py +46 -4
- camel/models/togetherai_model.py +38 -3
- camel/models/vllm_model.py +37 -3
- camel/models/yi_model.py +36 -3
- camel/models/zhipuai_model.py +38 -3
- camel/retrievers/__init__.py +3 -0
- camel/retrievers/hybrid_retrival.py +237 -0
- camel/toolkits/__init__.py +20 -3
- camel/toolkits/arxiv_toolkit.py +2 -1
- camel/toolkits/ask_news_toolkit.py +4 -2
- camel/toolkits/audio_analysis_toolkit.py +238 -0
- camel/toolkits/base.py +22 -3
- camel/toolkits/code_execution.py +2 -0
- camel/toolkits/dappier_toolkit.py +2 -1
- camel/toolkits/data_commons_toolkit.py +38 -12
- camel/toolkits/excel_toolkit.py +172 -0
- camel/toolkits/function_tool.py +13 -0
- camel/toolkits/github_toolkit.py +5 -1
- camel/toolkits/google_maps_toolkit.py +2 -1
- camel/toolkits/google_scholar_toolkit.py +2 -0
- camel/toolkits/human_toolkit.py +0 -3
- camel/toolkits/image_analysis_toolkit.py +202 -0
- camel/toolkits/linkedin_toolkit.py +3 -2
- camel/toolkits/meshy_toolkit.py +3 -2
- camel/toolkits/mineru_toolkit.py +178 -0
- camel/toolkits/networkx_toolkit.py +240 -0
- camel/toolkits/notion_toolkit.py +2 -0
- camel/toolkits/openbb_toolkit.py +3 -2
- camel/toolkits/page_script.js +376 -0
- camel/toolkits/reddit_toolkit.py +11 -3
- camel/toolkits/retrieval_toolkit.py +6 -1
- camel/toolkits/semantic_scholar_toolkit.py +2 -1
- camel/toolkits/stripe_toolkit.py +8 -2
- camel/toolkits/sympy_toolkit.py +44 -1
- camel/toolkits/video_analysis_toolkit.py +407 -0
- camel/toolkits/{video_toolkit.py → video_download_toolkit.py} +21 -25
- camel/toolkits/web_toolkit.py +1307 -0
- camel/toolkits/whatsapp_toolkit.py +3 -2
- camel/toolkits/zapier_toolkit.py +191 -0
- camel/types/__init__.py +2 -2
- camel/types/agents/__init__.py +16 -0
- camel/types/agents/tool_calling_record.py +52 -0
- camel/types/enums.py +3 -0
- camel/types/openai_types.py +16 -14
- camel/utils/__init__.py +2 -1
- camel/utils/async_func.py +2 -2
- camel/utils/commons.py +114 -1
- camel/verifiers/__init__.py +23 -0
- camel/verifiers/base.py +340 -0
- camel/verifiers/models.py +82 -0
- camel/verifiers/python_verifier.py +202 -0
- camel_ai-0.2.23.dist-info/METADATA +671 -0
- {camel_ai-0.2.21.dist-info → camel_ai-0.2.23.dist-info}/RECORD +127 -99
- {camel_ai-0.2.21.dist-info → camel_ai-0.2.23.dist-info}/WHEEL +1 -1
- camel_ai-0.2.21.dist-info/METADATA +0 -528
- {camel_ai-0.2.21.dist-info → camel_ai-0.2.23.dist-info/licenses}/LICENSE +0 -0
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import logging
|
|
15
15
|
from typing import Any, Dict, List, Optional, Union
|
|
16
16
|
|
|
17
|
+
from camel.toolkits import FunctionTool
|
|
17
18
|
from camel.toolkits.base import BaseToolkit
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
@@ -35,8 +36,18 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
35
36
|
Refer to https://datacommons.org/browser/ for more details.
|
|
36
37
|
"""
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
def __init__(self, timeout: Optional[float] = None):
|
|
40
|
+
r"""Initialize the DataCommonsToolkit.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
timeout (Optional[float], optional): Maximum time in seconds to
|
|
44
|
+
wait for API calls to complete. If None, will wait indefinitely.
|
|
45
|
+
(default: :obj:`None`)
|
|
46
|
+
"""
|
|
47
|
+
super().__init__(timeout=timeout)
|
|
48
|
+
|
|
39
49
|
def query_data_commons(
|
|
50
|
+
self,
|
|
40
51
|
query_string: str,
|
|
41
52
|
) -> Optional[List[Dict[str, Any]]]:
|
|
42
53
|
r"""Query the Data Commons knowledge graph using SPARQL.
|
|
@@ -76,9 +87,8 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
76
87
|
)
|
|
77
88
|
return None
|
|
78
89
|
|
|
79
|
-
@staticmethod
|
|
80
90
|
def get_triples(
|
|
81
|
-
dcids: Union[str, List[str]], limit: int = 500
|
|
91
|
+
self, dcids: Union[str, List[str]], limit: int = 500
|
|
82
92
|
) -> Optional[Dict[str, List[tuple]]]:
|
|
83
93
|
r"""Retrieve triples associated with nodes.
|
|
84
94
|
|
|
@@ -117,8 +127,8 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
117
127
|
logger.error(f"An error occurred: {e!s}")
|
|
118
128
|
return None
|
|
119
129
|
|
|
120
|
-
@staticmethod
|
|
121
130
|
def get_stat_time_series(
|
|
131
|
+
self,
|
|
122
132
|
place: str,
|
|
123
133
|
stat_var: str,
|
|
124
134
|
measurement_method: Optional[str] = None,
|
|
@@ -166,9 +176,8 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
166
176
|
)
|
|
167
177
|
return None
|
|
168
178
|
|
|
169
|
-
@staticmethod
|
|
170
179
|
def get_property_labels(
|
|
171
|
-
dcids: Union[str, List[str]], out: bool = True
|
|
180
|
+
self, dcids: Union[str, List[str]], out: bool = True
|
|
172
181
|
) -> Optional[Dict[str, List[str]]]:
|
|
173
182
|
r"""Retrieves and analyzes property labels for given DCIDs.
|
|
174
183
|
|
|
@@ -195,8 +204,8 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
195
204
|
)
|
|
196
205
|
return None
|
|
197
206
|
|
|
198
|
-
@staticmethod
|
|
199
207
|
def get_property_values(
|
|
208
|
+
self,
|
|
200
209
|
dcids: Union[str, List[str]],
|
|
201
210
|
prop: str,
|
|
202
211
|
out: Optional[bool] = True,
|
|
@@ -239,9 +248,8 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
239
248
|
)
|
|
240
249
|
return None
|
|
241
250
|
|
|
242
|
-
@staticmethod
|
|
243
251
|
def get_places_in(
|
|
244
|
-
dcids: list, place_type: str
|
|
252
|
+
self, dcids: list, place_type: str
|
|
245
253
|
) -> Optional[Dict[str, Any]]:
|
|
246
254
|
r"""Retrieves places within a given place type.
|
|
247
255
|
|
|
@@ -269,8 +277,8 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
269
277
|
)
|
|
270
278
|
return None
|
|
271
279
|
|
|
272
|
-
@staticmethod
|
|
273
280
|
def get_stat_value(
|
|
281
|
+
self,
|
|
274
282
|
place: str,
|
|
275
283
|
stat_var: str,
|
|
276
284
|
date: Optional[str] = None,
|
|
@@ -326,8 +334,7 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
326
334
|
)
|
|
327
335
|
return None
|
|
328
336
|
|
|
329
|
-
|
|
330
|
-
def get_stat_all(places: str, stat_vars: str) -> Optional[dict]:
|
|
337
|
+
def get_stat_all(self, places: str, stat_vars: str) -> Optional[dict]:
|
|
331
338
|
r"""Retrieves the value of a statistical variable for a given place
|
|
332
339
|
and date.
|
|
333
340
|
|
|
@@ -358,3 +365,22 @@ class DataCommonsToolkit(BaseToolkit):
|
|
|
358
365
|
f"statistical variable: {e!s}"
|
|
359
366
|
)
|
|
360
367
|
return None
|
|
368
|
+
|
|
369
|
+
def get_tools(self) -> List[FunctionTool]:
|
|
370
|
+
r"""Returns a list of FunctionTool objects representing the functions
|
|
371
|
+
in the toolkit.
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
List[FunctionTool]: A list of FunctionTool objects representing
|
|
375
|
+
the functions in the toolkit.
|
|
376
|
+
"""
|
|
377
|
+
return [
|
|
378
|
+
FunctionTool(self.query_data_commons),
|
|
379
|
+
FunctionTool(self.get_triples),
|
|
380
|
+
FunctionTool(self.get_stat_time_series),
|
|
381
|
+
FunctionTool(self.get_property_labels),
|
|
382
|
+
FunctionTool(self.get_property_values),
|
|
383
|
+
FunctionTool(self.get_places_in),
|
|
384
|
+
FunctionTool(self.get_stat_value),
|
|
385
|
+
FunctionTool(self.get_stat_all),
|
|
386
|
+
]
|
|
@@ -0,0 +1,172 @@
|
|
|
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
|
+
|
|
15
|
+
from typing import List
|
|
16
|
+
|
|
17
|
+
import pandas as pd
|
|
18
|
+
|
|
19
|
+
from camel.logger import get_logger
|
|
20
|
+
from camel.toolkits.base import BaseToolkit
|
|
21
|
+
from camel.toolkits.function_tool import FunctionTool
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ExcelToolkit(BaseToolkit):
|
|
27
|
+
r"""A class representing a toolkit for extract detailed cell information
|
|
28
|
+
from an Excel file.
|
|
29
|
+
|
|
30
|
+
This class provides method for processing docx, pdf, pptx, etc. It cannot
|
|
31
|
+
process excel files.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def _convert_to_markdown(self, df: pd.DataFrame) -> str:
|
|
35
|
+
r"""Convert DataFrame to Markdown format table.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
df (pd.DataFrame): DataFrame containing the Excel data.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
str: Markdown formatted table.
|
|
42
|
+
"""
|
|
43
|
+
from tabulate import tabulate
|
|
44
|
+
|
|
45
|
+
md_table = tabulate(df, headers='keys', tablefmt='pipe')
|
|
46
|
+
return str(md_table)
|
|
47
|
+
|
|
48
|
+
def extract_excel_content(self, document_path: str) -> str:
|
|
49
|
+
r"""Extract detailed cell information from an Excel file, including
|
|
50
|
+
multiple sheets.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
document_path (str): The path of the Excel file.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
str: Extracted excel information, including details of each sheet.
|
|
57
|
+
"""
|
|
58
|
+
from openpyxl import load_workbook
|
|
59
|
+
from xls2xlsx import XLS2XLSX
|
|
60
|
+
|
|
61
|
+
logger.debug(
|
|
62
|
+
f"Calling extract_excel_content with document_path"
|
|
63
|
+
f": {document_path}"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if not (
|
|
67
|
+
document_path.endswith("xls")
|
|
68
|
+
or document_path.endswith("xlsx")
|
|
69
|
+
or document_path.endswith("csv")
|
|
70
|
+
):
|
|
71
|
+
logger.error("Only xls, xlsx, csv files are supported.")
|
|
72
|
+
return (
|
|
73
|
+
f"Failed to process file {document_path}: "
|
|
74
|
+
f"It is not excel format. Please try other ways."
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if document_path.endswith("csv"):
|
|
78
|
+
try:
|
|
79
|
+
df = pd.read_csv(document_path)
|
|
80
|
+
md_table = self._convert_to_markdown(df)
|
|
81
|
+
return f"CSV File Processed:\n{md_table}"
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.error(f"Failed to process file {document_path}: {e}")
|
|
84
|
+
return f"Failed to process file {document_path}: {e}"
|
|
85
|
+
|
|
86
|
+
if document_path.endswith("xls"):
|
|
87
|
+
output_path = document_path.replace(".xls", ".xlsx")
|
|
88
|
+
x2x = XLS2XLSX(document_path)
|
|
89
|
+
x2x.to_xlsx(output_path)
|
|
90
|
+
document_path = output_path
|
|
91
|
+
|
|
92
|
+
# Load the Excel workbook
|
|
93
|
+
wb = load_workbook(document_path, data_only=True)
|
|
94
|
+
sheet_info_list = []
|
|
95
|
+
|
|
96
|
+
# Iterate through all sheets
|
|
97
|
+
for sheet in wb.sheetnames:
|
|
98
|
+
ws = wb[sheet]
|
|
99
|
+
cell_info_list = []
|
|
100
|
+
|
|
101
|
+
for row in ws.iter_rows():
|
|
102
|
+
for cell in row:
|
|
103
|
+
row_num = cell.row
|
|
104
|
+
col_letter = cell.column_letter
|
|
105
|
+
|
|
106
|
+
cell_value = cell.value
|
|
107
|
+
|
|
108
|
+
font_color = None
|
|
109
|
+
if (
|
|
110
|
+
cell.font
|
|
111
|
+
and cell.font.color
|
|
112
|
+
and "rgb=None" not in str(cell.font.color)
|
|
113
|
+
): # Handle font color
|
|
114
|
+
font_color = cell.font.color.rgb
|
|
115
|
+
|
|
116
|
+
fill_color = None
|
|
117
|
+
if (
|
|
118
|
+
cell.fill
|
|
119
|
+
and cell.fill.fgColor
|
|
120
|
+
and "rgb=None" not in str(cell.fill.fgColor)
|
|
121
|
+
): # Handle fill color
|
|
122
|
+
fill_color = cell.fill.fgColor.rgb
|
|
123
|
+
|
|
124
|
+
cell_info_list.append(
|
|
125
|
+
{
|
|
126
|
+
"index": f"{row_num}{col_letter}",
|
|
127
|
+
"value": cell_value,
|
|
128
|
+
"font_color": font_color,
|
|
129
|
+
"fill_color": fill_color,
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Convert the sheet to a DataFrame and then to markdown
|
|
134
|
+
sheet_df = pd.read_excel(
|
|
135
|
+
document_path, sheet_name=sheet, engine='openpyxl'
|
|
136
|
+
)
|
|
137
|
+
markdown_content = self._convert_to_markdown(sheet_df)
|
|
138
|
+
|
|
139
|
+
# Collect all information for the sheet
|
|
140
|
+
sheet_info = {
|
|
141
|
+
"sheet_name": sheet,
|
|
142
|
+
"cell_info_list": cell_info_list,
|
|
143
|
+
"markdown_content": markdown_content,
|
|
144
|
+
}
|
|
145
|
+
sheet_info_list.append(sheet_info)
|
|
146
|
+
|
|
147
|
+
result_str = ""
|
|
148
|
+
for sheet_info in sheet_info_list:
|
|
149
|
+
result_str += f"""
|
|
150
|
+
Sheet Name: {sheet_info['sheet_name']}
|
|
151
|
+
Cell information list:
|
|
152
|
+
{sheet_info['cell_info_list']}
|
|
153
|
+
|
|
154
|
+
Markdown View of the content:
|
|
155
|
+
{sheet_info['markdown_content']}
|
|
156
|
+
|
|
157
|
+
{'-'*40}
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
return result_str
|
|
161
|
+
|
|
162
|
+
def get_tools(self) -> List[FunctionTool]:
|
|
163
|
+
r"""Returns a list of FunctionTool objects representing the functions
|
|
164
|
+
in the toolkit.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
List[FunctionTool]: A list of FunctionTool objects representing
|
|
168
|
+
the functions in the toolkit.
|
|
169
|
+
"""
|
|
170
|
+
return [
|
|
171
|
+
FunctionTool(self.extract_excel_content),
|
|
172
|
+
]
|
camel/toolkits/function_tool.py
CHANGED
|
@@ -398,6 +398,19 @@ class FunctionTool:
|
|
|
398
398
|
f"Error: {e}"
|
|
399
399
|
)
|
|
400
400
|
|
|
401
|
+
async def async_call(self, *args: Any, **kwargs: Any) -> Any:
|
|
402
|
+
if self.synthesize_output:
|
|
403
|
+
result = self.synthesize_execution_output(args, kwargs)
|
|
404
|
+
return result
|
|
405
|
+
if self.is_async:
|
|
406
|
+
return await self.func(*args, **kwargs)
|
|
407
|
+
else:
|
|
408
|
+
return self.func(*args, **kwargs)
|
|
409
|
+
|
|
410
|
+
@property
|
|
411
|
+
def is_async(self) -> bool:
|
|
412
|
+
return inspect.iscoroutinefunction(self.func)
|
|
413
|
+
|
|
401
414
|
@staticmethod
|
|
402
415
|
def validate_openai_tool_schema(
|
|
403
416
|
openai_tool_schema: Dict[str, Any],
|
camel/toolkits/github_toolkit.py
CHANGED
|
@@ -39,7 +39,10 @@ class GithubToolkit(BaseToolkit):
|
|
|
39
39
|
|
|
40
40
|
@dependencies_required('github')
|
|
41
41
|
def __init__(
|
|
42
|
-
self,
|
|
42
|
+
self,
|
|
43
|
+
repo_name: str,
|
|
44
|
+
access_token: Optional[str] = None,
|
|
45
|
+
timeout: Optional[float] = None,
|
|
43
46
|
) -> None:
|
|
44
47
|
r"""Initializes a new instance of the GitHubToolkit class.
|
|
45
48
|
|
|
@@ -49,6 +52,7 @@ class GithubToolkit(BaseToolkit):
|
|
|
49
52
|
with GitHub. If not provided, it will be obtained using the
|
|
50
53
|
`get_github_access_token` method.
|
|
51
54
|
"""
|
|
55
|
+
super().__init__(timeout=timeout)
|
|
52
56
|
from github import Auth, Github
|
|
53
57
|
|
|
54
58
|
if access_token is None:
|
|
@@ -101,7 +101,8 @@ class GoogleMapsToolkit(BaseToolkit):
|
|
|
101
101
|
"""
|
|
102
102
|
|
|
103
103
|
@dependencies_required('googlemaps')
|
|
104
|
-
def __init__(self) -> None:
|
|
104
|
+
def __init__(self, timeout: Optional[float] = None) -> None:
|
|
105
|
+
super().__init__(timeout=timeout)
|
|
105
106
|
import googlemaps
|
|
106
107
|
|
|
107
108
|
api_key = os.environ.get('GOOGLE_API_KEY')
|
|
@@ -39,6 +39,7 @@ class GoogleScholarToolkit(BaseToolkit):
|
|
|
39
39
|
use_free_proxies: bool = False,
|
|
40
40
|
proxy_http: Optional[str] = None,
|
|
41
41
|
proxy_https: Optional[str] = None,
|
|
42
|
+
timeout: Optional[float] = None,
|
|
42
43
|
) -> None:
|
|
43
44
|
r"""Initializes the GoogleScholarToolkit with the author's identifier.
|
|
44
45
|
|
|
@@ -54,6 +55,7 @@ class GoogleScholarToolkit(BaseToolkit):
|
|
|
54
55
|
proxy_https ( Optional[str]): Proxy https address pass to pg.
|
|
55
56
|
SingleProxy. (default: :obj:`None`)
|
|
56
57
|
"""
|
|
58
|
+
super().__init__(timeout=timeout)
|
|
57
59
|
from scholarly import ProxyGenerator, scholarly
|
|
58
60
|
|
|
59
61
|
# Set Free Proxies is needed
|
camel/toolkits/human_toolkit.py
CHANGED
|
@@ -24,9 +24,6 @@ logger = logging.getLogger(__name__)
|
|
|
24
24
|
class HumanToolkit(BaseToolkit):
|
|
25
25
|
r"""A class representing a toolkit for human interaction."""
|
|
26
26
|
|
|
27
|
-
def __init__(self):
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
27
|
def ask_human_via_console(self, question: str) -> str:
|
|
31
28
|
r"""Ask a question to the human via the console.
|
|
32
29
|
|
|
@@ -0,0 +1,202 @@
|
|
|
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
|
+
|
|
15
|
+
from io import BytesIO
|
|
16
|
+
from typing import List, Optional
|
|
17
|
+
from urllib.parse import urlparse
|
|
18
|
+
|
|
19
|
+
import requests
|
|
20
|
+
from PIL import Image
|
|
21
|
+
|
|
22
|
+
from camel.logger import get_logger
|
|
23
|
+
from camel.messages import BaseMessage
|
|
24
|
+
from camel.models import BaseModelBackend, ModelFactory
|
|
25
|
+
from camel.toolkits import FunctionTool
|
|
26
|
+
from camel.toolkits.base import BaseToolkit
|
|
27
|
+
from camel.types import ModelPlatformType, ModelType
|
|
28
|
+
|
|
29
|
+
logger = get_logger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ImageAnalysisToolkit(BaseToolkit):
|
|
33
|
+
r"""A toolkit for comprehensive image analysis and understanding.
|
|
34
|
+
The toolkit uses vision-capable language models to perform these tasks.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, model: Optional[BaseModelBackend] = None):
|
|
38
|
+
r"""Initialize the ImageAnalysisToolkit.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
model (Optional[BaseModelBackend]): The model backend to use for
|
|
42
|
+
image analysis tasks. This model should support processing
|
|
43
|
+
images for tasks like image description and visual question
|
|
44
|
+
answering. If None, a default model will be created using
|
|
45
|
+
ModelFactory. (default: :obj:`None`)
|
|
46
|
+
"""
|
|
47
|
+
if model:
|
|
48
|
+
self.model = model
|
|
49
|
+
else:
|
|
50
|
+
self.model = ModelFactory.create(
|
|
51
|
+
model_platform=ModelPlatformType.DEFAULT,
|
|
52
|
+
model_type=ModelType.DEFAULT,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def image_to_text(
|
|
56
|
+
self, image_path: str, sys_prompt: Optional[str] = None
|
|
57
|
+
) -> str:
|
|
58
|
+
r"""Generates textual description of an image with optional custom
|
|
59
|
+
prompt.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
image_path (str): Local path or URL to an image file.
|
|
63
|
+
sys_prompt (Optional[str]): Custom system prompt for the analysis.
|
|
64
|
+
(default: :obj:`None`)
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
str: Natural language description of the image.
|
|
68
|
+
"""
|
|
69
|
+
default_content = '''You are an image analysis expert. Provide a
|
|
70
|
+
detailed description including text if present.'''
|
|
71
|
+
|
|
72
|
+
system_msg = BaseMessage.make_assistant_message(
|
|
73
|
+
role_name="Senior Computer Vision Analyst",
|
|
74
|
+
content=sys_prompt if sys_prompt else default_content,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return self._analyze_image(
|
|
78
|
+
image_path=image_path,
|
|
79
|
+
prompt="Please describe the contents of this image.",
|
|
80
|
+
system_message=system_msg,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def ask_question_about_image(
|
|
84
|
+
self, image_path: str, question: str, sys_prompt: Optional[str] = None
|
|
85
|
+
) -> str:
|
|
86
|
+
r"""Answers image questions with optional custom instructions.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
image_path (str): Local path or URL to an image file.
|
|
90
|
+
question (str): Query about the image content.
|
|
91
|
+
sys_prompt (Optional[str]): Custom system prompt for the analysis.
|
|
92
|
+
(default: :obj:`None`)
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
str: Detailed answer based on visual understanding
|
|
96
|
+
"""
|
|
97
|
+
default_content = """Answer questions about images by:
|
|
98
|
+
1. Careful visual inspection
|
|
99
|
+
2. Contextual reasoning
|
|
100
|
+
3. Text transcription where relevant
|
|
101
|
+
4. Logical deduction from visual evidence"""
|
|
102
|
+
|
|
103
|
+
system_msg = BaseMessage.make_assistant_message(
|
|
104
|
+
role_name="Visual QA Specialist",
|
|
105
|
+
content=sys_prompt if sys_prompt else default_content,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return self._analyze_image(
|
|
109
|
+
image_path=image_path,
|
|
110
|
+
prompt=question,
|
|
111
|
+
system_message=system_msg,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def _load_image(self, image_path: str) -> Image.Image:
|
|
115
|
+
r"""Loads an image from either local path or URL.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
image_path (str): Local path or URL to image.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Image.Image: Loaded PIL Image object.
|
|
122
|
+
|
|
123
|
+
Raises:
|
|
124
|
+
ValueError: For invalid paths/URLs or unreadable images.
|
|
125
|
+
requests.exceptions.RequestException: For URL fetch failures.
|
|
126
|
+
"""
|
|
127
|
+
parsed = urlparse(image_path)
|
|
128
|
+
|
|
129
|
+
if parsed.scheme in ("http", "https"):
|
|
130
|
+
logger.debug(f"Fetching image from URL: {image_path}")
|
|
131
|
+
try:
|
|
132
|
+
response = requests.get(image_path, timeout=15)
|
|
133
|
+
response.raise_for_status()
|
|
134
|
+
return Image.open(BytesIO(response.content))
|
|
135
|
+
except requests.exceptions.RequestException as e:
|
|
136
|
+
logger.error(f"URL fetch failed: {e}")
|
|
137
|
+
raise
|
|
138
|
+
else:
|
|
139
|
+
logger.debug(f"Loading local image: {image_path}")
|
|
140
|
+
try:
|
|
141
|
+
return Image.open(image_path)
|
|
142
|
+
except Exception as e:
|
|
143
|
+
logger.error(f"Image loading failed: {e}")
|
|
144
|
+
raise ValueError(f"Invalid image file: {e}")
|
|
145
|
+
|
|
146
|
+
def _analyze_image(
|
|
147
|
+
self,
|
|
148
|
+
image_path: str,
|
|
149
|
+
prompt: str,
|
|
150
|
+
system_message: BaseMessage,
|
|
151
|
+
) -> str:
|
|
152
|
+
r"""Core analysis method handling image loading and processing.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
image_path (str): Image location.
|
|
156
|
+
prompt (str): Analysis query/instructions.
|
|
157
|
+
system_message (BaseMessage): Custom system prompt for the
|
|
158
|
+
analysis.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
str: Analysis result or error message.
|
|
162
|
+
"""
|
|
163
|
+
try:
|
|
164
|
+
image = self._load_image(image_path)
|
|
165
|
+
logger.info(f"Analyzing image: {image_path}")
|
|
166
|
+
|
|
167
|
+
from camel.agents.chat_agent import ChatAgent
|
|
168
|
+
|
|
169
|
+
agent = ChatAgent(
|
|
170
|
+
system_message=system_message,
|
|
171
|
+
model=self.model,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
user_msg = BaseMessage.make_user_message(
|
|
175
|
+
role_name="User",
|
|
176
|
+
content=prompt,
|
|
177
|
+
image_list=[image],
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
response = agent.step(user_msg)
|
|
181
|
+
agent.reset()
|
|
182
|
+
return response.msgs[0].content
|
|
183
|
+
|
|
184
|
+
except (ValueError, requests.exceptions.RequestException) as e:
|
|
185
|
+
logger.error(f"Image handling error: {e}")
|
|
186
|
+
return f"Image error: {e!s}"
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.error(f"Unexpected error: {e}")
|
|
189
|
+
return f"Analysis failed: {e!s}"
|
|
190
|
+
|
|
191
|
+
def get_tools(self) -> List[FunctionTool]:
|
|
192
|
+
r"""Returns a list of FunctionTool objects representing the functions
|
|
193
|
+
in the toolkit.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
List[FunctionTool]: A list of FunctionTool objects representing the
|
|
197
|
+
functions in the toolkit.
|
|
198
|
+
"""
|
|
199
|
+
return [
|
|
200
|
+
FunctionTool(self.image_to_text),
|
|
201
|
+
FunctionTool(self.ask_question_about_image),
|
|
202
|
+
]
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import json
|
|
16
16
|
import os
|
|
17
17
|
from http import HTTPStatus
|
|
18
|
-
from typing import List
|
|
18
|
+
from typing import List, Optional
|
|
19
19
|
|
|
20
20
|
import requests
|
|
21
21
|
|
|
@@ -33,7 +33,8 @@ class LinkedInToolkit(BaseToolkit):
|
|
|
33
33
|
retrieving the authenticated user's profile information.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
def __init__(self):
|
|
36
|
+
def __init__(self, timeout: Optional[float] = None):
|
|
37
|
+
super().__init__(timeout=timeout)
|
|
37
38
|
self._access_token = self._get_access_token()
|
|
38
39
|
|
|
39
40
|
def create_post(self, text: str) -> dict:
|
camel/toolkits/meshy_toolkit.py
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
|
-
from typing import Any, Dict
|
|
16
|
+
from typing import Any, Dict, Optional
|
|
17
17
|
|
|
18
18
|
import requests
|
|
19
19
|
|
|
@@ -38,10 +38,11 @@ class MeshyToolkit(BaseToolkit):
|
|
|
38
38
|
(None, 'MESHY_API_KEY'),
|
|
39
39
|
]
|
|
40
40
|
)
|
|
41
|
-
def __init__(self):
|
|
41
|
+
def __init__(self, timeout: Optional[float] = None):
|
|
42
42
|
r"""Initializes the MeshyToolkit with the API key from the
|
|
43
43
|
environment.
|
|
44
44
|
"""
|
|
45
|
+
super().__init__(timeout=timeout)
|
|
45
46
|
self.api_key = os.getenv('MESHY_API_KEY')
|
|
46
47
|
|
|
47
48
|
def generate_3d_preview(
|