camel-ai 0.2.69a1__py3-none-any.whl → 0.2.69a2__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 CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  from camel.logger import disable_logging, enable_logging, set_log_level
16
16
 
17
- __version__ = '0.2.69a1'
17
+ __version__ = '0.2.69a2'
18
18
 
19
19
  __all__ = [
20
20
  '__version__',
@@ -286,8 +286,8 @@ class SingleAgentWorker(Worker):
286
286
  )
287
287
  except Exception as e:
288
288
  print(
289
- f"{Fore.RED}Error occurred while processing task {task.id}:"
290
- f"\n{e}{Fore.RESET}"
289
+ f"{Fore.RED}Error processing task {task.id}: "
290
+ f"{type(e).__name__}: {e}{Fore.RESET}"
291
291
  )
292
292
  return TaskState.FAILED
293
293
  finally:
@@ -336,8 +336,15 @@ class SingleAgentWorker(Worker):
336
336
 
337
337
  print(f"======\n{Fore.GREEN}Reply from {self}:{Fore.RESET}")
338
338
 
339
- result_dict = json.loads(response.msg.content)
340
- task_result = TaskResult(**result_dict)
339
+ try:
340
+ result_dict = json.loads(response.msg.content)
341
+ task_result = TaskResult(**result_dict)
342
+ except json.JSONDecodeError as e:
343
+ print(
344
+ f"{Fore.RED}JSON parsing error for task {task.id}: "
345
+ f"Invalid response format - {e}{Fore.RESET}"
346
+ )
347
+ return TaskState.FAILED
341
348
 
342
349
  color = Fore.RED if task_result.failed else Fore.GREEN
343
350
  print(
@@ -882,11 +882,16 @@ class Workforce(BaseNode):
882
882
  self._task = task
883
883
  self._state = WorkforceState.RUNNING
884
884
  task.state = TaskState.FAILED # TODO: Add logic for OPEN
885
- self._pending_tasks.append(task)
886
885
 
887
886
  # Decompose the task into subtasks first
888
887
  subtasks = self._decompose_task(task)
889
- self._pending_tasks.extendleft(reversed(subtasks))
888
+ if subtasks:
889
+ # If decomposition happened, the original task becomes a container.
890
+ # We only execute its subtasks.
891
+ self._pending_tasks.extendleft(reversed(subtasks))
892
+ else:
893
+ # If no decomposition, execute the original task.
894
+ self._pending_tasks.append(task)
890
895
  self.set_channel(TaskChannel())
891
896
 
892
897
  # Save initial snapshot
@@ -531,9 +531,10 @@ class FunctionTool:
531
531
  param_dict = properties[param_name]
532
532
  if "description" not in param_dict:
533
533
  warnings.warn(
534
- f"Parameter description is missing "
535
- f"for {param_dict}. This may affect the "
536
- f"quality of tool calling."
534
+ f"Parameter description is missing for the "
535
+ f"function '{openai_tool_schema['function']['name']}'. "
536
+ f"The parameter definition is {param_dict}. "
537
+ f"This may affect the quality of tool calling."
537
538
  )
538
539
 
539
540
  def get_openai_tool_schema(self) -> Dict[str, Any]:
@@ -17,6 +17,7 @@ from __future__ import annotations
17
17
 
18
18
  import io
19
19
  import os
20
+ import re
20
21
  import tempfile
21
22
  from pathlib import Path
22
23
  from typing import List, Optional
@@ -41,6 +42,11 @@ VIDEO_QA_PROMPT = """
41
42
  Analyze the provided video frames and corresponding audio transcription to \
42
43
  answer the given question(s) thoroughly and accurately.
43
44
 
45
+ The transcriptions may come from two sources:
46
+ 1. **Audio Transcription**: The spoken words in the video.
47
+ 2. **Visual Text (OCR)**: Text extracted from the video frames (like \
48
+ captions, on-screen text, etc.).
49
+
44
50
  Instructions:
45
51
  1. Visual Analysis:
46
52
  - Examine the video frames to identify visible entities.
@@ -49,11 +55,13 @@ such as size, color, shape, texture, or behavior.
49
55
  - Note significant groupings, interactions, or contextual patterns \
50
56
  relevant to the analysis.
51
57
 
52
- 2. Audio Integration:
58
+ 2. Audio and Text Integration:
53
59
  - Use the audio transcription to complement or clarify your visual \
54
60
  observations.
61
+ - Use the visual text (OCR) to get exact textual information that may \
62
+ not be accurately readable from the images alone.
55
63
  - Identify names, descriptions, or contextual hints in the \
56
- transcription that help confirm or refine your visual analysis.
64
+ transcriptions that help confirm or refine your visual analysis.
57
65
 
58
66
  3. Detailed Reasoning and Justification:
59
67
  - Provide a brief explanation of how you identified and distinguished \
@@ -65,7 +73,7 @@ your reasoning.
65
73
  - Specify the total number of distinct species or object types \
66
74
  identified in the video.
67
75
  - Describe the defining characteristics and any supporting evidence \
68
- from the video and transcription.
76
+ from the video and transcription sources.
69
77
 
70
78
  5. Important Considerations:
71
79
  - Pay close attention to subtle differences that could distinguish \
@@ -76,6 +84,9 @@ similar-looking species or objects
76
84
  **Audio Transcription:**
77
85
  {audio_transcription}
78
86
 
87
+ **Visual Text (OCR):**
88
+ {visual_text}
89
+
79
90
  **Question:**
80
91
  {question}
81
92
  """
@@ -96,6 +107,8 @@ class VideoAnalysisToolkit(BaseToolkit):
96
107
  transcription using OpenAI's audio models. Requires a valid OpenAI
97
108
  API key. When disabled, video analysis will be based solely on
98
109
  visual content. (default: :obj:`False`)
110
+ use_ocr (bool, optional): Whether to enable OCR for extracting text
111
+ from video frames. (default: :obj:`False`)
99
112
  frame_interval (float, optional): Interval in seconds between frames
100
113
  to extract from the video. (default: :obj:`4.0`)
101
114
  output_language (str, optional): The language for output responses.
@@ -113,6 +126,7 @@ class VideoAnalysisToolkit(BaseToolkit):
113
126
  download_directory: Optional[str] = None,
114
127
  model: Optional[BaseModelBackend] = None,
115
128
  use_audio_transcription: bool = False,
129
+ use_ocr: bool = False,
116
130
  frame_interval: float = 4.0,
117
131
  output_language: str = "English",
118
132
  cookies_path: Optional[str] = None,
@@ -122,6 +136,7 @@ class VideoAnalysisToolkit(BaseToolkit):
122
136
  self._cleanup = download_directory is None
123
137
  self._temp_files: list[str] = [] # Track temporary files for cleanup
124
138
  self._use_audio_transcription = use_audio_transcription
139
+ self._use_ocr = use_ocr
125
140
  self.output_language = output_language
126
141
  self.frame_interval = frame_interval
127
142
 
@@ -211,6 +226,53 @@ class VideoAnalysisToolkit(BaseToolkit):
211
226
  f"{self._download_directory}: {e}"
212
227
  )
213
228
 
229
+ @dependencies_required("pytesseract", "cv2", "numpy")
230
+ def _extract_text_from_frame(self, frame: Image.Image) -> str:
231
+ r"""Extract text from a video frame using OCR.
232
+
233
+ Args:
234
+ frame (Image.Image): PIL image frame to process.
235
+
236
+ Returns:
237
+ str: Extracted text from the frame.
238
+ """
239
+ import cv2
240
+ import numpy as np
241
+ import pytesseract
242
+
243
+ try:
244
+ # Convert to OpenCV format for preprocessing
245
+ cv_image = cv2.cvtColor(np.array(frame), cv2.COLOR_RGB2BGR)
246
+
247
+ # Preprocessing for better OCR results
248
+ gray = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
249
+ blur = cv2.GaussianBlur(gray, (3, 3), 0)
250
+ _, threshold = cv2.threshold(
251
+ blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU
252
+ )
253
+
254
+ # Convert back to PIL image for OCR
255
+ preprocessed_frame = Image.fromarray(threshold)
256
+ return pytesseract.image_to_string(preprocessed_frame).strip()
257
+ except Exception as e:
258
+ logger.error(f"OCR failed: {e}")
259
+ return ""
260
+
261
+ def _process_extracted_text(self, text: str) -> str:
262
+ r"""Clean and format OCR-extracted text.
263
+
264
+ Args:
265
+ text (str): Raw extracted OCR text.
266
+
267
+ Returns:
268
+ str: Cleaned and formatted text.
269
+ """
270
+ # Filter irrelevant characters and noise
271
+ text = re.sub(r'[^\w\s,.?!:;\'"()-]', '', text)
272
+ # Remove excessive whitespace
273
+ text = re.sub(r'\s+', ' ', text).strip()
274
+ return text
275
+
214
276
  def _extract_audio_from_video(
215
277
  self, video_path: str, output_format: str = "mp3"
216
278
  ) -> str:
@@ -511,9 +573,21 @@ class VideoAnalysisToolkit(BaseToolkit):
511
573
  audio_path = self._extract_audio_from_video(video_path)
512
574
  audio_transcript = self._transcribe_audio(audio_path)
513
575
 
576
+ # Extract visual text with OCR
577
+ visual_text = ""
514
578
  video_frames = self._extract_keyframes(video_path)
579
+ # Build visual text only if OCR is enabled
580
+ if self._use_ocr:
581
+ for frame in video_frames:
582
+ text = self._extract_text_from_frame(frame)
583
+ processed = self._process_extracted_text(text)
584
+ if processed:
585
+ visual_text += processed + "\n"
586
+ visual_text = visual_text.strip() or "No visual text detected."
587
+
515
588
  prompt = VIDEO_QA_PROMPT.format(
516
589
  audio_transcription=audio_transcript,
590
+ visual_text=visual_text,
517
591
  question=question,
518
592
  )
519
593
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.69a1
3
+ Version: 0.2.69a2
4
4
  Summary: Communicative Agents for AI Society Study
5
5
  Project-URL: Homepage, https://www.camel-ai.org/
6
6
  Project-URL: Repository, https://github.com/camel-ai/camel
@@ -99,6 +99,7 @@ Requires-Dist: pymupdf<2,>=1.22.5; extra == 'all'
99
99
  Requires-Dist: pyobvector>=0.1.18; extra == 'all'
100
100
  Requires-Dist: pyowm<4,>=3.3.0; extra == 'all'
101
101
  Requires-Dist: pytelegrambotapi<5,>=4.18.0; extra == 'all'
102
+ Requires-Dist: pytesseract>=0.3.13; extra == 'all'
102
103
  Requires-Dist: pytest-asyncio<0.24,>=0.23.0; extra == 'all'
103
104
  Requires-Dist: pytest-cov<5,>=4; extra == 'all'
104
105
  Requires-Dist: pytest<8,>=7; extra == 'all'
@@ -226,6 +227,7 @@ Provides-Extra: media-tools
226
227
  Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'media-tools'
227
228
  Requires-Dist: imageio[pyav]<3,>=2.34.2; extra == 'media-tools'
228
229
  Requires-Dist: pydub<0.26,>=0.25.1; extra == 'media-tools'
230
+ Requires-Dist: pytesseract>=0.3.13; extra == 'media-tools'
229
231
  Requires-Dist: scenedetect>=0.6.5.2; extra == 'media-tools'
230
232
  Requires-Dist: yt-dlp<2025,>=2024.11.4; extra == 'media-tools'
231
233
  Provides-Extra: model-platforms
@@ -252,6 +254,7 @@ Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'owl'
252
254
  Requires-Dist: fpdf>=1.7.2; extra == 'owl'
253
255
  Requires-Dist: html2text>=2024.2.26; extra == 'owl'
254
256
  Requires-Dist: imageio[pyav]<3,>=2.34.2; extra == 'owl'
257
+ Requires-Dist: markitdown==0.1.1; extra == 'owl'
255
258
  Requires-Dist: mcp-server-fetch==2025.1.17; extra == 'owl'
256
259
  Requires-Dist: mcp-simple-arxiv==0.2.2; extra == 'owl'
257
260
  Requires-Dist: newspaper3k<0.3,>=0.2.8; extra == 'owl'
@@ -266,6 +269,7 @@ Requires-Dist: pyautogui<0.10,>=0.9.54; extra == 'owl'
266
269
  Requires-Dist: pydub<0.26,>=0.25.1; extra == 'owl'
267
270
  Requires-Dist: pylatex>=1.4.2; extra == 'owl'
268
271
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'owl'
272
+ Requires-Dist: pytesseract>=0.3.13; extra == 'owl'
269
273
  Requires-Dist: python-dotenv<2,>=1.0.0; extra == 'owl'
270
274
  Requires-Dist: python-pptx>=1.0.2; extra == 'owl'
271
275
  Requires-Dist: requests-oauthlib<2,>=1.3.1; extra == 'owl'
@@ -1,4 +1,4 @@
1
- camel/__init__.py,sha256=1jdrogMF4lEAc0fG6MGwLdfMt_c4luht9mj7KUDk-ts,901
1
+ camel/__init__.py,sha256=WMfYI5vXSsv0CSAsfpSAJsK0QJ-RqKRd4nHzG-3LE7Q,901
2
2
  camel/generators.py,sha256=JRqj9_m1PF4qT6UtybzTQ-KBT9MJQt18OAAYvQ_fr2o,13844
3
3
  camel/human.py,sha256=Xg8x1cS5KK4bQ1SDByiHZnzsRpvRP-KZViNvmu38xo4,5475
4
4
  camel/logger.py,sha256=rZVeOVYuQ9RYJ5Tqyv0usqy0g4zaVEq4qSfZ9nd2640,5755
@@ -273,11 +273,11 @@ camel/societies/workforce/__init__.py,sha256=bkTI-PE-MSK9AQ2V2gR6cR2WY-R7Jqy_NmX
273
273
  camel/societies/workforce/base.py,sha256=z2DmbTP5LL5-aCAAqglznQqCLfPmnyM5zD3w6jjtsb8,2175
274
274
  camel/societies/workforce/prompts.py,sha256=_l7OUkzH5p7KOd8HMZle9zB9W3jKza_Yb_6elFKiZ2s,11813
275
275
  camel/societies/workforce/role_playing_worker.py,sha256=pWPCtkLx-xbc4SWyZBfMwvWr-R5ZpANhN7g6PDuH8Po,7615
276
- camel/societies/workforce/single_agent_worker.py,sha256=NIP0cHueDNQZxzN-MikmwIe-1LoT3V8Z1LgqdiPidCE,14438
276
+ camel/societies/workforce/single_agent_worker.py,sha256=5lF9zzxDJMCtELh6Y407m_D2bMAXMsY3yvY3_Bssd5A,14704
277
277
  camel/societies/workforce/task_channel.py,sha256=uqQQI67Tr4awbR4bjZXdx8_4gL6-ON5IjQk_H_ryqT4,7431
278
278
  camel/societies/workforce/utils.py,sha256=Gjlz7pLo4r1b6iNHtlIMxeEuat4d6tEEQMI40JAU3kY,6190
279
279
  camel/societies/workforce/worker.py,sha256=36tkOyz4G2wfBdrFjt9NBPXsx4UbE6uL5on8sP2aoqk,6414
280
- camel/societies/workforce/workforce.py,sha256=gLbjcGeAXwHCyk6jGs7mBHJnpEG7xcvEcwjA2ibi6-0,88526
280
+ camel/societies/workforce/workforce.py,sha256=xiWLSoRHOC1yz9WK0uXImwQkblr7XIJ6BXdNrEUf7Rk,88755
281
281
  camel/societies/workforce/workforce_logger.py,sha256=2xGMMYQPphC5WlPbgWWp9SEY2hGpP-GkhgsNC19irns,24237
282
282
  camel/storages/__init__.py,sha256=bFpvvAS2QyZoIr-tnwhMWsZRL411kIRq6IMUHcI7KHs,1989
283
283
  camel/storages/graph_storages/__init__.py,sha256=G29BNn651C0WTOpjCl4QnVM-4B9tcNh8DdmsCiONH8Y,948
@@ -327,7 +327,7 @@ camel/toolkits/dappier_toolkit.py,sha256=OEHOYXX_oXhgbVtWYAy13nO9uXf9i5qEXSwY4Pe
327
327
  camel/toolkits/data_commons_toolkit.py,sha256=aHZUSL1ACpnYGaf1rE2csVKTmXTmN8lMGRUBYhZ_YEk,14168
328
328
  camel/toolkits/excel_toolkit.py,sha256=DSjBXl24_LrJubGFFmB_vqliKzzWTbT1TH309YQVUO8,6653
329
329
  camel/toolkits/file_write_toolkit.py,sha256=i1CivjvqTpHakYK_EynNvNikjZZYsusxkjT2v-f9EYc,16473
330
- camel/toolkits/function_tool.py,sha256=045I_vyqvB6PorcoVaEbxYjGe-fD-FBKtO4lfpZ2eVw,33535
330
+ camel/toolkits/function_tool.py,sha256=xCDzjxTRCVj_kmbnMFBuwK-3NuzM4JNe_kv9HLtjnIA,33644
331
331
  camel/toolkits/github_toolkit.py,sha256=iUyRrjWGAW_iljZVfNyfkm1Vi55wJxK6PsDAQs9pOag,13099
332
332
  camel/toolkits/google_calendar_toolkit.py,sha256=E-sdgdbtNBs_CXbhht9t1dsVr4DsTr5NguHkx4fvSmc,15410
333
333
  camel/toolkits/google_maps_toolkit.py,sha256=WTnkURpGri9KcY5OwV7AJJHOzmpu5RNmYE1QCVqvwWM,12023
@@ -365,7 +365,7 @@ camel/toolkits/task_planning_toolkit.py,sha256=Ttw9fHae4omGC1SA-6uaeXVHJ1YkwiVlo
365
365
  camel/toolkits/terminal_toolkit.py,sha256=gupuTvNkwnFzcFwDB_irSJ9-dXRr8yEAsYq5ChEkkHg,37230
366
366
  camel/toolkits/thinking_toolkit.py,sha256=nZYLvKWIx2BM1DYu69I9B5EISAG7aYcLYXKv9663BVk,8000
367
367
  camel/toolkits/twitter_toolkit.py,sha256=Px4N8aUxUzy01LhGSWkdrC2JgwKkrY3cvxgMeJ2XYfU,15939
368
- camel/toolkits/video_analysis_toolkit.py,sha256=Mf7kZ2UDKFzIq8XjJc6EhL8qXQnEomQ8OBy_eyjD49A,20647
368
+ camel/toolkits/video_analysis_toolkit.py,sha256=Wh08MAVvs3PtgXN88Sk0TXYaGfVmQAol8FPCXMPPpIM,23375
369
369
  camel/toolkits/video_download_toolkit.py,sha256=jBb2SQ9OA5HIuGF7FbNQ0KrvvwMWPxUnvUyCHjbHuQQ,7501
370
370
  camel/toolkits/weather_toolkit.py,sha256=fs9x9aC38Wsvni6A4PPpbRX6-aBnZiqs2Jix39yoULU,7413
371
371
  camel/toolkits/whatsapp_toolkit.py,sha256=udUQXkXyeWsmrUlOJZsGBhHtc_jhB05Axe_TchhibsU,5760
@@ -431,7 +431,7 @@ camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo
431
431
  camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
432
432
  camel/verifiers/physics_verifier.py,sha256=c1grrRddcrVN7szkxhv2QirwY9viIRSITWeWFF5HmLs,30187
433
433
  camel/verifiers/python_verifier.py,sha256=ogTz77wODfEcDN4tMVtiSkRQyoiZbHPY2fKybn59lHw,20558
434
- camel_ai-0.2.69a1.dist-info/METADATA,sha256=jl-Gs6_fECtoyaAusXMrlvSrTx1WvMmSAx39z4biZT8,44837
435
- camel_ai-0.2.69a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
436
- camel_ai-0.2.69a1.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
437
- camel_ai-0.2.69a1.dist-info/RECORD,,
434
+ camel_ai-0.2.69a2.dist-info/METADATA,sha256=5FBG-fY28g9tYIZIpxESs4biHcejU3mVLUQY5sMepWk,45047
435
+ camel_ai-0.2.69a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
436
+ camel_ai-0.2.69a2.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
437
+ camel_ai-0.2.69a2.dist-info/RECORD,,