camel-ai 0.2.57__py3-none-any.whl → 0.2.58__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.

@@ -0,0 +1,204 @@
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 concurrent.futures import ThreadPoolExecutor, as_completed
16
+ from typing import ClassVar, Dict, List, Optional
17
+
18
+ from camel.logger import get_logger
19
+
20
+ logger = get_logger(__name__)
21
+
22
+
23
+ class MarkItDownLoader:
24
+ r"""MarkitDown convert various file types into Markdown format.
25
+
26
+ Supported Input Formats:
27
+ - PDF
28
+ - Microsoft Office documents:
29
+ - Word (.doc, .docx)
30
+ - Excel (.xls, .xlsx)
31
+ - PowerPoint (.ppt, .pptx)
32
+ - EPUB
33
+ - HTML
34
+ - Images (with EXIF metadata and OCR support)
35
+ - Audio files (with EXIF metadata and speech transcription)
36
+ - Text-based formats:
37
+ - CSV
38
+ - JSON
39
+ - XML
40
+ - ZIP archives (iterates over contents)
41
+ - YouTube URLs (via transcript extraction)
42
+ """
43
+
44
+ SUPPORTED_FORMATS: ClassVar[List[str]] = [
45
+ ".pdf",
46
+ ".doc",
47
+ ".docx",
48
+ ".xls",
49
+ ".xlsx",
50
+ ".ppt",
51
+ ".pptx",
52
+ ".epub",
53
+ ".html",
54
+ ".htm",
55
+ ".jpg",
56
+ ".jpeg",
57
+ ".png",
58
+ ".mp3",
59
+ ".wav",
60
+ ".csv",
61
+ ".json",
62
+ ".xml",
63
+ ".zip",
64
+ ".txt",
65
+ ]
66
+
67
+ def __init__(
68
+ self,
69
+ llm_client: Optional[object] = None,
70
+ llm_model: Optional[str] = None,
71
+ ):
72
+ r"""Initializes the Converter.
73
+
74
+ Args:
75
+ llm_client (Optional[object]): Optional client for LLM integration.
76
+ (default: :obj:`None`)
77
+ llm_model (Optional[str]): Optional model name for the LLM.
78
+ (default: :obj:`None`)
79
+ """
80
+ from markitdown import MarkItDown
81
+
82
+ try:
83
+ self.converter = MarkItDown(
84
+ llm_client=llm_client, llm_model=llm_model
85
+ )
86
+ logger.info("MarkItDownLoader initialized successfully.")
87
+ except Exception as e:
88
+ logger.error(f"Failed to initialize MarkItDown Converter: {e}")
89
+ raise Exception(f"Failed to initialize MarkItDown Converter: {e}")
90
+
91
+ def _validate_format(self, file_path: str) -> bool:
92
+ r"""Validates if the file format is supported.
93
+
94
+ Args:
95
+ file_path (str): Path to the input file.
96
+
97
+ Returns:
98
+ bool: True if the format is supported, False otherwise.
99
+ """
100
+ _, ext = os.path.splitext(file_path)
101
+ return ext.lower() in self.SUPPORTED_FORMATS
102
+
103
+ def convert_file(self, file_path: str) -> str:
104
+ r"""Converts the given file to Markdown format.
105
+
106
+ Args:
107
+ file_path (str): Path to the input file.
108
+
109
+ Returns:
110
+ str: Converted Markdown text.
111
+
112
+ Raises:
113
+ FileNotFoundError: If the specified file does not exist.
114
+ ValueError: If the file format is not supported.
115
+ Exception: For other errors during conversion.
116
+ """
117
+ if not os.path.isfile(file_path):
118
+ logger.error(f"File not found: {file_path}")
119
+ raise FileNotFoundError(f"File not found: {file_path}")
120
+
121
+ if not self._validate_format(file_path):
122
+ logger.error(
123
+ f"Unsupported file format: {file_path}."
124
+ f"Supported formats are "
125
+ f"{MarkItDownLoader.SUPPORTED_FORMATS}"
126
+ )
127
+ raise ValueError(f"Unsupported file format: {file_path}")
128
+
129
+ try:
130
+ logger.info(f"Converting file: {file_path}")
131
+ result = self.converter.convert(file_path)
132
+ logger.info(f"File converted successfully: {file_path}")
133
+ return result.text_content
134
+ except Exception as e:
135
+ logger.error(f"Error converting file '{file_path}': {e}")
136
+ raise Exception(f"Error converting file '{file_path}': {e}")
137
+
138
+ def convert_files(
139
+ self,
140
+ file_paths: List[str],
141
+ parallel: bool = False,
142
+ skip_failed: bool = False,
143
+ ) -> Dict[str, str]:
144
+ r"""Converts multiple files to Markdown format.
145
+
146
+ Args:
147
+ file_paths (List[str]): List of file paths to convert.
148
+ parallel (bool): Whether to process files in parallel.
149
+ (default: :obj:`False`)
150
+ skip_failed (bool): Whether to skip failed files instead
151
+ of including error messages.
152
+ (default: :obj:`False`)
153
+
154
+ Returns:
155
+ Dict[str, str]: Dictionary mapping file paths to their
156
+ converted Markdown text.
157
+
158
+ Raises:
159
+ Exception: For errors during conversion of any file if
160
+ skip_failed is False.
161
+ """
162
+ from tqdm.auto import tqdm
163
+
164
+ converted_files = {}
165
+
166
+ if parallel:
167
+ with ThreadPoolExecutor() as executor:
168
+ future_to_path = {
169
+ executor.submit(self.convert_file, path): path
170
+ for path in file_paths
171
+ }
172
+ for future in tqdm(
173
+ as_completed(future_to_path),
174
+ total=len(file_paths),
175
+ desc="Converting files (parallel)",
176
+ ):
177
+ path = future_to_path[future]
178
+ try:
179
+ converted_files[path] = future.result()
180
+ except Exception as e:
181
+ if skip_failed:
182
+ logger.warning(
183
+ f"Skipping file '{path}' due to error: {e}"
184
+ )
185
+ else:
186
+ logger.error(
187
+ f"Error processing file '{path}': {e}"
188
+ )
189
+ converted_files[path] = f"Error: {e}"
190
+ else:
191
+ for path in tqdm(file_paths, desc="Converting files (sequential)"):
192
+ try:
193
+ logger.info(f"Processing file: {path}")
194
+ converted_files[path] = self.convert_file(path)
195
+ except Exception as e:
196
+ if skip_failed:
197
+ logger.warning(
198
+ f"Skipping file '{path}' due to error: {e}"
199
+ )
200
+ else:
201
+ logger.error(f"Error processing file '{path}': {e}")
202
+ converted_files[path] = f"Error: {e}"
203
+
204
+ return converted_files
@@ -16,7 +16,7 @@ import os
16
16
  from json import JSONDecodeError
17
17
  from typing import Any, Dict, List, Optional, Type, Union
18
18
 
19
- from openai import AsyncOpenAI, AsyncStream, OpenAI, Stream
19
+ from openai import AsyncOpenAI, AsyncStream, BadRequestError, OpenAI, Stream
20
20
  from pydantic import BaseModel, ValidationError
21
21
 
22
22
  from camel.logger import get_logger
@@ -198,7 +198,7 @@ class OpenAICompatibleModel(BaseModelBackend):
198
198
  model=self.model_type,
199
199
  **request_config,
200
200
  )
201
- except (ValidationError, JSONDecodeError) as e:
201
+ except (ValidationError, JSONDecodeError, BadRequestError) as e:
202
202
  logger.warning(
203
203
  f"Format validation error: {e}. "
204
204
  f"Attempting fallback with JSON format."
@@ -237,7 +237,7 @@ class OpenAICompatibleModel(BaseModelBackend):
237
237
  model=self.model_type,
238
238
  **request_config,
239
239
  )
240
- except (ValidationError, JSONDecodeError) as e:
240
+ except (ValidationError, JSONDecodeError, BadRequestError) as e:
241
241
  logger.warning(
242
242
  f"Format validation error: {e}. "
243
243
  f"Attempting fallback with JSON format."
@@ -41,7 +41,7 @@ from camel.societies.workforce.utils import (
41
41
  )
42
42
  from camel.societies.workforce.worker import Worker
43
43
  from camel.tasks.task import Task, TaskState
44
- from camel.toolkits import GoogleMapsToolkit, SearchToolkit, WeatherToolkit
44
+ from camel.toolkits import CodeExecutionToolkit, SearchToolkit, ThinkingToolkit
45
45
  from camel.types import ModelPlatformType, ModelType
46
46
 
47
47
  logger = get_logger(__name__)
@@ -370,9 +370,9 @@ class Workforce(BaseNode):
370
370
 
371
371
  # Default tools for a new agent
372
372
  function_list = [
373
- *SearchToolkit().get_tools(),
374
- *WeatherToolkit().get_tools(),
375
- *GoogleMapsToolkit().get_tools(),
373
+ SearchToolkit().search_duckduckgo,
374
+ *CodeExecutionToolkit().get_tools(),
375
+ *ThinkingToolkit().get_tools(),
376
376
  ]
377
377
 
378
378
  model_config_dict = ChatGPTConfig(
@@ -59,6 +59,7 @@ from .video_analysis_toolkit import VideoAnalysisToolkit
59
59
  from .image_analysis_toolkit import ImageAnalysisToolkit
60
60
  from .mcp_toolkit import MCPToolkit
61
61
  from .browser_toolkit import BrowserToolkit
62
+ from .async_browser_toolkit import AsyncBrowserToolkit
62
63
  from .file_write_toolkit import FileWriteToolkit
63
64
  from .terminal_toolkit import TerminalToolkit
64
65
  from .pubmed_toolkit import PubMedToolkit
@@ -72,6 +73,7 @@ from .pulse_mcp_search_toolkit import PulseMCPSearchToolkit
72
73
  from .klavis_toolkit import KlavisToolkit
73
74
  from .aci_toolkit import ACIToolkit
74
75
  from .playwright_mcp_toolkit import PlaywrightMCPToolkit
76
+ from .wolfram_alpha_toolkit import WolframAlphaToolkit
75
77
 
76
78
 
77
79
  __all__ = [
@@ -119,6 +121,7 @@ __all__ = [
119
121
  'VideoAnalysisToolkit',
120
122
  'ImageAnalysisToolkit',
121
123
  'BrowserToolkit',
124
+ 'AsyncBrowserToolkit',
122
125
  'FileWriteToolkit',
123
126
  'TerminalToolkit',
124
127
  'PubMedToolkit',
@@ -132,4 +135,5 @@ __all__ = [
132
135
  'KlavisToolkit',
133
136
  'ACIToolkit',
134
137
  'PlaywrightMCPToolkit',
138
+ 'WolframAlphaToolkit',
135
139
  ]