camel-ai 0.2.9__py3-none-any.whl → 0.2.11__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 +10 -5
- camel/agents/__init__.py +4 -4
- camel/agents/base.py +4 -4
- camel/agents/chat_agent.py +106 -42
- camel/agents/critic_agent.py +4 -4
- camel/agents/deductive_reasoner_agent.py +8 -5
- camel/agents/embodied_agent.py +4 -4
- camel/agents/knowledge_graph_agent.py +4 -4
- camel/agents/role_assignment_agent.py +4 -4
- camel/agents/search_agent.py +4 -4
- camel/agents/task_agent.py +4 -4
- camel/agents/tool_agents/__init__.py +4 -4
- camel/agents/tool_agents/base.py +4 -4
- camel/agents/tool_agents/hugging_face_tool_agent.py +4 -4
- camel/bots/__init__.py +4 -4
- camel/bots/discord_app.py +4 -4
- camel/bots/slack/__init__.py +4 -4
- camel/bots/slack/models.py +4 -4
- camel/bots/slack/slack_app.py +4 -4
- camel/bots/telegram_bot.py +4 -4
- camel/configs/__init__.py +13 -4
- camel/configs/anthropic_config.py +4 -4
- camel/configs/base_config.py +4 -4
- camel/configs/cohere_config.py +76 -0
- camel/configs/deepseek_config.py +134 -0
- camel/configs/gemini_config.py +85 -127
- camel/configs/groq_config.py +4 -4
- camel/configs/litellm_config.py +4 -4
- camel/configs/mistral_config.py +4 -7
- camel/configs/nvidia_config.py +70 -0
- camel/configs/ollama_config.py +4 -4
- camel/configs/openai_config.py +32 -7
- camel/configs/qwen_config.py +4 -4
- camel/configs/reka_config.py +4 -4
- camel/configs/samba_config.py +4 -4
- camel/configs/togetherai_config.py +4 -4
- camel/configs/vllm_config.py +14 -5
- camel/configs/yi_config.py +4 -4
- camel/configs/zhipuai_config.py +4 -4
- camel/embeddings/__init__.py +6 -4
- camel/embeddings/base.py +4 -4
- camel/embeddings/mistral_embedding.py +4 -4
- camel/embeddings/openai_compatible_embedding.py +91 -0
- camel/embeddings/openai_embedding.py +4 -4
- camel/embeddings/sentence_transformers_embeddings.py +4 -4
- camel/embeddings/vlm_embedding.py +8 -5
- camel/generators.py +4 -4
- camel/human.py +4 -4
- camel/interpreters/__init__.py +4 -4
- camel/interpreters/base.py +4 -4
- camel/interpreters/docker_interpreter.py +11 -6
- camel/interpreters/internal_python_interpreter.py +4 -4
- camel/interpreters/interpreter_error.py +4 -4
- camel/interpreters/ipython_interpreter.py +4 -4
- camel/interpreters/subprocess_interpreter.py +11 -6
- camel/loaders/__init__.py +4 -4
- camel/loaders/apify_reader.py +4 -4
- camel/loaders/base_io.py +4 -4
- camel/loaders/chunkr_reader.py +4 -4
- camel/loaders/firecrawl_reader.py +4 -7
- camel/loaders/jina_url_reader.py +4 -4
- camel/loaders/unstructured_io.py +4 -4
- camel/logger.py +112 -0
- camel/memories/__init__.py +4 -4
- camel/memories/agent_memories.py +4 -4
- camel/memories/base.py +4 -4
- camel/memories/blocks/__init__.py +4 -4
- camel/memories/blocks/chat_history_block.py +4 -4
- camel/memories/blocks/vectordb_block.py +4 -4
- camel/memories/context_creators/__init__.py +4 -4
- camel/memories/context_creators/score_based.py +4 -4
- camel/memories/records.py +4 -4
- camel/messages/__init__.py +20 -4
- camel/messages/base.py +118 -11
- camel/messages/conversion/__init__.py +31 -0
- camel/messages/conversion/alpaca.py +122 -0
- camel/messages/conversion/conversation_models.py +178 -0
- camel/messages/conversion/sharegpt/__init__.py +20 -0
- camel/messages/conversion/sharegpt/function_call_formatter.py +49 -0
- camel/messages/conversion/sharegpt/hermes/__init__.py +19 -0
- camel/messages/conversion/sharegpt/hermes/hermes_function_formatter.py +128 -0
- camel/messages/func_message.py +50 -4
- camel/models/__init__.py +13 -4
- camel/models/anthropic_model.py +4 -4
- camel/models/azure_openai_model.py +4 -4
- camel/models/base_model.py +4 -4
- camel/models/cohere_model.py +282 -0
- camel/models/deepseek_model.py +139 -0
- camel/models/gemini_model.py +61 -146
- camel/models/groq_model.py +4 -4
- camel/models/litellm_model.py +4 -4
- camel/models/mistral_model.py +4 -4
- camel/models/model_factory.py +13 -4
- camel/models/model_manager.py +212 -0
- camel/models/nemotron_model.py +4 -4
- camel/models/nvidia_model.py +141 -0
- camel/models/ollama_model.py +4 -4
- camel/models/openai_audio_models.py +4 -4
- camel/models/openai_compatible_model.py +4 -4
- camel/models/openai_model.py +43 -4
- camel/models/qwen_model.py +4 -4
- camel/models/reka_model.py +4 -4
- camel/models/samba_model.py +6 -5
- camel/models/stub_model.py +4 -4
- camel/models/togetherai_model.py +4 -4
- camel/models/vllm_model.py +4 -4
- camel/models/yi_model.py +4 -4
- camel/models/zhipuai_model.py +4 -4
- camel/personas/__init__.py +17 -0
- camel/personas/persona.py +103 -0
- camel/personas/persona_hub.py +293 -0
- camel/prompts/__init__.py +6 -4
- camel/prompts/ai_society.py +4 -4
- camel/prompts/base.py +4 -4
- camel/prompts/code.py +4 -4
- camel/prompts/evaluation.py +4 -4
- camel/prompts/generate_text_embedding_data.py +4 -4
- camel/prompts/image_craft.py +4 -4
- camel/prompts/misalignment.py +4 -4
- camel/prompts/multi_condition_image_craft.py +4 -4
- camel/prompts/object_recognition.py +4 -4
- camel/prompts/persona_hub.py +61 -0
- camel/prompts/prompt_templates.py +4 -4
- camel/prompts/role_description_prompt_template.py +4 -4
- camel/prompts/solution_extraction.py +4 -4
- camel/prompts/task_prompt_template.py +4 -4
- camel/prompts/translation.py +4 -4
- camel/prompts/video_description_prompt.py +4 -4
- camel/responses/__init__.py +4 -4
- camel/responses/agent_responses.py +4 -4
- camel/retrievers/__init__.py +4 -4
- camel/retrievers/auto_retriever.py +4 -4
- camel/retrievers/base.py +4 -4
- camel/retrievers/bm25_retriever.py +4 -4
- camel/retrievers/cohere_rerank_retriever.py +7 -9
- camel/retrievers/vector_retriever.py +26 -9
- camel/runtime/__init__.py +29 -0
- camel/runtime/api.py +93 -0
- camel/runtime/base.py +45 -0
- camel/runtime/configs.py +56 -0
- camel/runtime/docker_runtime.py +404 -0
- camel/runtime/llm_guard_runtime.py +199 -0
- camel/runtime/remote_http_runtime.py +204 -0
- camel/runtime/utils/__init__.py +20 -0
- camel/runtime/utils/function_risk_toolkit.py +58 -0
- camel/runtime/utils/ignore_risk_toolkit.py +72 -0
- camel/schemas/__init__.py +17 -0
- camel/schemas/base.py +45 -0
- camel/schemas/openai_converter.py +116 -0
- camel/societies/__init__.py +4 -4
- camel/societies/babyagi_playing.py +8 -5
- camel/societies/role_playing.py +4 -4
- camel/societies/workforce/__init__.py +4 -4
- camel/societies/workforce/base.py +4 -4
- camel/societies/workforce/prompts.py +4 -4
- camel/societies/workforce/role_playing_worker.py +4 -4
- camel/societies/workforce/single_agent_worker.py +4 -4
- camel/societies/workforce/task_channel.py +4 -4
- camel/societies/workforce/utils.py +4 -4
- camel/societies/workforce/worker.py +4 -4
- camel/societies/workforce/workforce.py +7 -7
- camel/storages/__init__.py +4 -4
- camel/storages/graph_storages/__init__.py +4 -4
- camel/storages/graph_storages/base.py +4 -4
- camel/storages/graph_storages/graph_element.py +4 -4
- camel/storages/graph_storages/nebula_graph.py +4 -4
- camel/storages/graph_storages/neo4j_graph.py +4 -4
- camel/storages/key_value_storages/__init__.py +4 -4
- camel/storages/key_value_storages/base.py +4 -4
- camel/storages/key_value_storages/in_memory.py +4 -4
- camel/storages/key_value_storages/json.py +4 -4
- camel/storages/key_value_storages/redis.py +4 -4
- camel/storages/object_storages/__init__.py +4 -4
- camel/storages/object_storages/amazon_s3.py +4 -4
- camel/storages/object_storages/azure_blob.py +4 -4
- camel/storages/object_storages/base.py +4 -4
- camel/storages/object_storages/google_cloud.py +4 -4
- camel/storages/vectordb_storages/__init__.py +4 -4
- camel/storages/vectordb_storages/base.py +4 -4
- camel/storages/vectordb_storages/milvus.py +4 -4
- camel/storages/vectordb_storages/qdrant.py +4 -4
- camel/tasks/__init__.py +4 -4
- camel/tasks/task.py +4 -4
- camel/tasks/task_prompt.py +4 -4
- camel/terminators/__init__.py +4 -4
- camel/terminators/base.py +4 -4
- camel/terminators/response_terminator.py +4 -4
- camel/terminators/token_limit_terminator.py +4 -4
- camel/toolkits/__init__.py +16 -17
- camel/toolkits/arxiv_toolkit.py +4 -4
- camel/toolkits/ask_news_toolkit.py +7 -18
- camel/toolkits/base.py +4 -4
- camel/toolkits/code_execution.py +57 -10
- camel/toolkits/dalle_toolkit.py +4 -7
- camel/toolkits/data_commons_toolkit.py +4 -4
- camel/toolkits/function_tool.py +220 -69
- camel/toolkits/github_toolkit.py +4 -4
- camel/toolkits/google_maps_toolkit.py +4 -4
- camel/toolkits/google_scholar_toolkit.py +4 -4
- camel/toolkits/human_toolkit.py +53 -0
- camel/toolkits/linkedin_toolkit.py +4 -4
- camel/toolkits/math_toolkit.py +4 -7
- camel/toolkits/meshy_toolkit.py +185 -0
- camel/toolkits/notion_toolkit.py +4 -4
- camel/toolkits/open_api_specs/biztoc/__init__.py +4 -4
- camel/toolkits/open_api_specs/coursera/__init__.py +4 -4
- camel/toolkits/open_api_specs/create_qr_code/__init__.py +4 -4
- camel/toolkits/open_api_specs/klarna/__init__.py +4 -4
- camel/toolkits/open_api_specs/nasa_apod/__init__.py +4 -4
- camel/toolkits/open_api_specs/outschool/__init__.py +4 -4
- camel/toolkits/open_api_specs/outschool/paths/__init__.py +4 -4
- camel/toolkits/open_api_specs/outschool/paths/get_classes.py +4 -4
- camel/toolkits/open_api_specs/outschool/paths/search_teachers.py +4 -4
- camel/toolkits/open_api_specs/security_config.py +4 -4
- camel/toolkits/open_api_specs/speak/__init__.py +4 -4
- camel/toolkits/open_api_specs/web_scraper/__init__.py +4 -4
- camel/toolkits/open_api_specs/web_scraper/paths/__init__.py +4 -4
- camel/toolkits/open_api_specs/web_scraper/paths/scraper.py +4 -4
- camel/toolkits/open_api_toolkit.py +4 -4
- camel/toolkits/reddit_toolkit.py +4 -4
- camel/toolkits/retrieval_toolkit.py +4 -4
- camel/toolkits/search_toolkit.py +49 -29
- camel/toolkits/slack_toolkit.py +4 -4
- camel/toolkits/twitter_toolkit.py +13 -13
- camel/toolkits/video_toolkit.py +211 -0
- camel/toolkits/weather_toolkit.py +4 -7
- camel/toolkits/whatsapp_toolkit.py +6 -6
- camel/types/__init__.py +6 -4
- camel/types/enums.py +118 -15
- camel/types/openai_types.py +6 -4
- camel/types/unified_model_type.py +9 -4
- camel/utils/__init__.py +35 -33
- camel/utils/async_func.py +4 -4
- camel/utils/commons.py +26 -9
- camel/utils/constants.py +4 -4
- camel/utils/response_format.py +63 -0
- camel/utils/token_counting.py +8 -5
- {camel_ai-0.2.9.dist-info → camel_ai-0.2.11.dist-info}/METADATA +108 -56
- camel_ai-0.2.11.dist-info/RECORD +252 -0
- camel_ai-0.2.9.dist-info/RECORD +0 -215
- {camel_ai-0.2.9.dist-info → camel_ai-0.2.11.dist-info}/LICENSE +0 -0
- {camel_ai-0.2.9.dist-info → camel_ai-0.2.11.dist-info}/WHEEL +0 -0
camel/toolkits/search_toolkit.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
5
5
|
#
|
|
6
6
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
#
|
|
8
8
|
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
#
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import os
|
|
15
15
|
import xml.etree.ElementTree as ET
|
|
16
16
|
from typing import Any, Dict, List, Union
|
|
@@ -274,7 +274,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
274
274
|
"""
|
|
275
275
|
import wolframalpha
|
|
276
276
|
|
|
277
|
-
WOLFRAMALPHA_APP_ID = os.environ.get(
|
|
277
|
+
WOLFRAMALPHA_APP_ID = os.environ.get("WOLFRAMALPHA_APP_ID")
|
|
278
278
|
if not WOLFRAMALPHA_APP_ID:
|
|
279
279
|
raise ValueError(
|
|
280
280
|
"`WOLFRAMALPHA_APP_ID` not found in environment "
|
|
@@ -315,27 +315,42 @@ class SearchToolkit(BaseToolkit):
|
|
|
315
315
|
"""
|
|
316
316
|
|
|
317
317
|
# Extract the original query
|
|
318
|
-
query = result.get(
|
|
318
|
+
query = result.get("@inputstring", "")
|
|
319
319
|
|
|
320
320
|
# Initialize a dictionary to hold structured output
|
|
321
321
|
output = {"query": query, "pod_info": [], "final_answer": None}
|
|
322
322
|
|
|
323
323
|
# Loop through each pod to extract the details
|
|
324
|
-
for pod in result.get(
|
|
324
|
+
for pod in result.get("pod", []):
|
|
325
|
+
# Handle the case where subpod might be a list
|
|
326
|
+
subpod_data = pod.get("subpod", {})
|
|
327
|
+
if isinstance(subpod_data, list):
|
|
328
|
+
# If it's a list, get the first item for 'plaintext' and 'img'
|
|
329
|
+
description, image_url = next(
|
|
330
|
+
(
|
|
331
|
+
(data["plaintext"], data["img"])
|
|
332
|
+
for data in subpod_data
|
|
333
|
+
if "plaintext" in data and "img" in data
|
|
334
|
+
),
|
|
335
|
+
("", ""),
|
|
336
|
+
)
|
|
337
|
+
else:
|
|
338
|
+
# Otherwise, handle it as a dictionary
|
|
339
|
+
description = subpod_data.get("plaintext", "")
|
|
340
|
+
image_url = subpod_data.get("img", {}).get("@src", "")
|
|
341
|
+
|
|
325
342
|
pod_info = {
|
|
326
|
-
"title": pod.get(
|
|
327
|
-
"description":
|
|
328
|
-
"image_url":
|
|
329
|
-
.get('img', {})
|
|
330
|
-
.get('@src', ''),
|
|
343
|
+
"title": pod.get("@title", ""),
|
|
344
|
+
"description": description,
|
|
345
|
+
"image_url": image_url,
|
|
331
346
|
}
|
|
332
347
|
|
|
333
348
|
# Add to steps list
|
|
334
349
|
output["pod_info"].append(pod_info)
|
|
335
350
|
|
|
336
351
|
# Get final answer
|
|
337
|
-
if pod.get(
|
|
338
|
-
output["final_answer"] =
|
|
352
|
+
if pod.get("@primary", False):
|
|
353
|
+
output["final_answer"] = description
|
|
339
354
|
|
|
340
355
|
return output
|
|
341
356
|
|
|
@@ -358,25 +373,33 @@ class SearchToolkit(BaseToolkit):
|
|
|
358
373
|
|
|
359
374
|
# Set up the query parameters
|
|
360
375
|
params = {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
376
|
+
"appid": app_id,
|
|
377
|
+
"input": query,
|
|
378
|
+
"podstate": ["Result__Step-by-step solution", "Show all steps"],
|
|
379
|
+
"format": "plaintext",
|
|
365
380
|
}
|
|
366
381
|
|
|
367
382
|
# Send the request
|
|
368
383
|
response = requests.get(url, params=params)
|
|
369
384
|
root = ET.fromstring(response.text)
|
|
370
385
|
|
|
371
|
-
# Extracting step-by-step
|
|
386
|
+
# Extracting step-by-step steps, including 'SBSStep' and 'SBSHintStep'
|
|
372
387
|
steps = []
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
388
|
+
# Find all subpods within the 'Results' pod
|
|
389
|
+
for subpod in root.findall(".//pod[@title='Results']//subpod"):
|
|
390
|
+
# Check if the subpod has the desired stepbystepcontenttype
|
|
391
|
+
content_type = subpod.find("stepbystepcontenttype")
|
|
392
|
+
if content_type is not None and content_type.text in [
|
|
393
|
+
"SBSStep",
|
|
394
|
+
"SBSHintStep",
|
|
395
|
+
]:
|
|
396
|
+
plaintext = subpod.find("plaintext")
|
|
397
|
+
if plaintext is not None and plaintext.text:
|
|
398
|
+
step_text = plaintext.text.strip()
|
|
399
|
+
cleaned_step = step_text.replace(
|
|
400
|
+
"Hint: |", ""
|
|
401
|
+
).strip() # Remove 'Hint: |' if present
|
|
402
|
+
steps.append(cleaned_step)
|
|
380
403
|
|
|
381
404
|
# Structuring the steps into a dictionary
|
|
382
405
|
structured_steps = {}
|
|
@@ -449,6 +472,3 @@ class SearchToolkit(BaseToolkit):
|
|
|
449
472
|
FunctionTool(self.query_wolfram_alpha),
|
|
450
473
|
FunctionTool(self.tavily_search),
|
|
451
474
|
]
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
SEARCH_FUNCS: List[FunctionTool] = SearchToolkit().get_tools()
|
camel/toolkits/slack_toolkit.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
5
5
|
#
|
|
6
6
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
#
|
|
8
8
|
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
#
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
5
5
|
#
|
|
6
6
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
#
|
|
8
8
|
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
#
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import datetime
|
|
15
15
|
import os
|
|
16
16
|
from http import HTTPStatus
|
|
@@ -20,12 +20,15 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
20
20
|
import requests
|
|
21
21
|
from requests_oauthlib import OAuth1
|
|
22
22
|
|
|
23
|
+
from camel.logger import get_logger
|
|
23
24
|
from camel.toolkits import FunctionTool
|
|
24
25
|
from camel.toolkits.base import BaseToolkit
|
|
25
26
|
from camel.utils import api_keys_required
|
|
26
27
|
|
|
27
28
|
TWEET_TEXT_LIMIT = 280
|
|
28
29
|
|
|
30
|
+
logger = get_logger(__name__)
|
|
31
|
+
|
|
29
32
|
|
|
30
33
|
@api_keys_required(
|
|
31
34
|
"TWITTER_CONSUMER_KEY",
|
|
@@ -407,14 +410,6 @@ def _handle_http_error(response: requests.Response) -> str:
|
|
|
407
410
|
return "Unexpected Exception"
|
|
408
411
|
|
|
409
412
|
|
|
410
|
-
TWITTER_FUNCS = [
|
|
411
|
-
FunctionTool(create_tweet),
|
|
412
|
-
FunctionTool(delete_tweet),
|
|
413
|
-
FunctionTool(get_my_user_profile),
|
|
414
|
-
FunctionTool(get_user_by_username),
|
|
415
|
-
]
|
|
416
|
-
|
|
417
|
-
|
|
418
413
|
class TwitterToolkit(BaseToolkit):
|
|
419
414
|
r"""A class representing a toolkit for Twitter operations.
|
|
420
415
|
|
|
@@ -442,4 +437,9 @@ class TwitterToolkit(BaseToolkit):
|
|
|
442
437
|
List[FunctionTool]: A list of FunctionTool objects
|
|
443
438
|
representing the functions in the toolkit.
|
|
444
439
|
"""
|
|
445
|
-
return
|
|
440
|
+
return [
|
|
441
|
+
FunctionTool(create_tweet),
|
|
442
|
+
FunctionTool(delete_tweet),
|
|
443
|
+
FunctionTool(get_my_user_profile),
|
|
444
|
+
FunctionTool(get_user_by_username),
|
|
445
|
+
]
|
|
@@ -0,0 +1,211 @@
|
|
|
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
|
+
import io
|
|
16
|
+
import logging
|
|
17
|
+
import re
|
|
18
|
+
import tempfile
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import List, Optional
|
|
21
|
+
|
|
22
|
+
from PIL import Image
|
|
23
|
+
|
|
24
|
+
from camel.toolkits.base import BaseToolkit
|
|
25
|
+
from camel.toolkits.function_tool import FunctionTool
|
|
26
|
+
from camel.utils import dependencies_required
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _standardize_url(url: str) -> str:
|
|
32
|
+
r"""Standardize the given URL."""
|
|
33
|
+
# Special case for YouTube embed URLs
|
|
34
|
+
if "youtube.com/embed/" in url:
|
|
35
|
+
match = re.search(r"embed/([a-zA-Z0-9_-]+)", url)
|
|
36
|
+
if match:
|
|
37
|
+
return f"https://www.youtube.com/watch?v={match.group(1)}"
|
|
38
|
+
else:
|
|
39
|
+
raise ValueError(f"Invalid YouTube URL: {url}")
|
|
40
|
+
|
|
41
|
+
return url
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _capture_screenshot(video_file: str, timestamp: float) -> Image.Image:
|
|
45
|
+
r"""Capture a screenshot from a video file at a specific timestamp.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
video_file (str): The path to the video file.
|
|
49
|
+
timestamp (float): The time in seconds from which to capture the
|
|
50
|
+
screenshot.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Image.Image: The captured screenshot in the form of Image.Image.
|
|
54
|
+
"""
|
|
55
|
+
import ffmpeg
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
out, _ = (
|
|
59
|
+
ffmpeg.input(video_file, ss=timestamp)
|
|
60
|
+
.filter('scale', 320, -1)
|
|
61
|
+
.output('pipe:', vframes=1, format='image2', vcodec='png')
|
|
62
|
+
.run(capture_stdout=True, capture_stderr=True)
|
|
63
|
+
)
|
|
64
|
+
except ffmpeg.Error as e:
|
|
65
|
+
raise RuntimeError(f"Failed to capture screenshot: {e.stderr}")
|
|
66
|
+
|
|
67
|
+
return Image.open(io.BytesIO(out))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class VideoDownloaderToolkit(BaseToolkit):
|
|
71
|
+
r"""A class for downloading videos and optionally splitting them into
|
|
72
|
+
chunks.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
download_directory (Optional[str], optional): The directory where the
|
|
76
|
+
video will be downloaded to. If not provided, video will be stored
|
|
77
|
+
in a temporary directory and will be cleaned up after use.
|
|
78
|
+
(default: :obj:`None`)
|
|
79
|
+
cookies_path (Optional[str], optional): The path to the cookies file
|
|
80
|
+
for the video service in Netscape format. (default: :obj:`None`)
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
@dependencies_required("yt_dlp", "ffmpeg")
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
download_directory: Optional[str] = None,
|
|
87
|
+
cookies_path: Optional[str] = None,
|
|
88
|
+
) -> None:
|
|
89
|
+
self._cleanup = download_directory is None
|
|
90
|
+
self._cookies_path = cookies_path
|
|
91
|
+
|
|
92
|
+
self._download_directory = Path(
|
|
93
|
+
download_directory or tempfile.mkdtemp()
|
|
94
|
+
).resolve()
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
self._download_directory.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
except FileExistsError:
|
|
99
|
+
raise ValueError(
|
|
100
|
+
f"{self._download_directory} is not a valid directory."
|
|
101
|
+
)
|
|
102
|
+
except OSError as e:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
f"Error creating directory {self._download_directory}: {e}"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
logger.info(f"Video will be downloaded to {self._download_directory}")
|
|
108
|
+
|
|
109
|
+
def __del__(self) -> None:
|
|
110
|
+
r"""Deconstructor for the VideoDownloaderToolkit class.
|
|
111
|
+
|
|
112
|
+
Cleans up the downloaded video if they are stored in a temporary
|
|
113
|
+
directory.
|
|
114
|
+
"""
|
|
115
|
+
import shutil
|
|
116
|
+
|
|
117
|
+
if self._cleanup:
|
|
118
|
+
shutil.rmtree(self._download_directory, ignore_errors=True)
|
|
119
|
+
|
|
120
|
+
def _download_video(self, url: str) -> str:
|
|
121
|
+
r"""Download the video and optionally split it into chunks.
|
|
122
|
+
|
|
123
|
+
yt-dlp will detect if the video is downloaded automatically so there
|
|
124
|
+
is no need to check if the video exists.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str: The path to the downloaded video file.
|
|
128
|
+
"""
|
|
129
|
+
import yt_dlp
|
|
130
|
+
|
|
131
|
+
video_template = self._download_directory / "%(title)s.%(ext)s"
|
|
132
|
+
ydl_opts = {
|
|
133
|
+
'format': 'bestvideo+bestaudio/best',
|
|
134
|
+
'outtmpl': str(video_template),
|
|
135
|
+
'force_generic_extractor': True,
|
|
136
|
+
'cookiefile': self._cookies_path,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
|
141
|
+
# Download the video and get the filename
|
|
142
|
+
logger.info(f"Downloading video from {url}...")
|
|
143
|
+
info = ydl.extract_info(url, download=True)
|
|
144
|
+
return ydl.prepare_filename(info)
|
|
145
|
+
except yt_dlp.utils.DownloadError as e:
|
|
146
|
+
raise RuntimeError(f"Failed to download video from {url}: {e}")
|
|
147
|
+
|
|
148
|
+
def get_video_bytes(
|
|
149
|
+
self,
|
|
150
|
+
video_url: str,
|
|
151
|
+
) -> bytes:
|
|
152
|
+
r"""Download video by the URL, and return the content in bytes.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
video_url (str): The URL of the video to download.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
bytes: The video file content in bytes.
|
|
159
|
+
"""
|
|
160
|
+
url = _standardize_url(video_url)
|
|
161
|
+
video_file = self._download_video(url)
|
|
162
|
+
|
|
163
|
+
with open(video_file, 'rb') as f:
|
|
164
|
+
video_bytes = f.read()
|
|
165
|
+
|
|
166
|
+
return video_bytes
|
|
167
|
+
|
|
168
|
+
def get_video_screenshots(
|
|
169
|
+
self, video_url: str, amount: int
|
|
170
|
+
) -> List[Image.Image]:
|
|
171
|
+
r"""Capture screenshots from the video at specified timestamps or by
|
|
172
|
+
dividing the video into equal parts if an integer is provided.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
video_url (str): The URL of the video to take screenshots.
|
|
176
|
+
amount (int): the amount of evenly split screenshots to capture.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List[Image.Image]: A list of screenshots as Image.Image.
|
|
180
|
+
"""
|
|
181
|
+
import ffmpeg
|
|
182
|
+
|
|
183
|
+
url = _standardize_url(video_url)
|
|
184
|
+
video_file = self._download_video(url)
|
|
185
|
+
|
|
186
|
+
# Get the video length
|
|
187
|
+
try:
|
|
188
|
+
probe = ffmpeg.probe(video_file)
|
|
189
|
+
video_length = float(probe['format']['duration'])
|
|
190
|
+
except ffmpeg.Error as e:
|
|
191
|
+
raise RuntimeError(f"Failed to determine video length: {e.stderr}")
|
|
192
|
+
|
|
193
|
+
interval = video_length / (amount + 1)
|
|
194
|
+
timestamps = [i * interval for i in range(1, amount + 1)]
|
|
195
|
+
|
|
196
|
+
images = [_capture_screenshot(video_file, ts) for ts in timestamps]
|
|
197
|
+
|
|
198
|
+
return images
|
|
199
|
+
|
|
200
|
+
def get_tools(self) -> List[FunctionTool]:
|
|
201
|
+
r"""Returns a list of FunctionTool objects representing the
|
|
202
|
+
functions in the toolkit.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
List[FunctionTool]: A list of FunctionTool objects representing
|
|
206
|
+
the functions in the toolkit.
|
|
207
|
+
"""
|
|
208
|
+
return [
|
|
209
|
+
FunctionTool(self.get_video_bytes),
|
|
210
|
+
FunctionTool(self.get_video_screenshots),
|
|
211
|
+
]
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
5
5
|
#
|
|
6
6
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
#
|
|
8
8
|
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
#
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import os
|
|
15
15
|
from typing import List, Literal
|
|
16
16
|
|
|
@@ -168,6 +168,3 @@ class WeatherToolkit(BaseToolkit):
|
|
|
168
168
|
return [
|
|
169
169
|
FunctionTool(self.get_weather_data),
|
|
170
170
|
]
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
WEATHER_FUNCS: List[FunctionTool] = WeatherToolkit().get_tools()
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
5
5
|
#
|
|
6
6
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
#
|
|
8
8
|
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
#
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
16
|
from typing import Any, Dict, List, Union
|
|
@@ -163,11 +163,11 @@ class WhatsAppToolkit(BaseToolkit):
|
|
|
163
163
|
return f"Failed to retrieve business profile: {e!s}"
|
|
164
164
|
|
|
165
165
|
def get_tools(self) -> List[FunctionTool]:
|
|
166
|
-
r"""Returns a list of
|
|
166
|
+
r"""Returns a list of FunctionTool objects representing the
|
|
167
167
|
functions in the toolkit.
|
|
168
168
|
|
|
169
169
|
Returns:
|
|
170
|
-
List[
|
|
170
|
+
List[FunctionTool]: A list of FunctionTool objects for the
|
|
171
171
|
toolkit methods.
|
|
172
172
|
"""
|
|
173
173
|
return [
|
camel/types/__init__.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
5
5
|
#
|
|
6
6
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
#
|
|
8
8
|
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
#
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
from .enums import (
|
|
15
15
|
AudioModelType,
|
|
16
16
|
EmbeddingModelType,
|
|
@@ -40,6 +40,7 @@ from .openai_types import (
|
|
|
40
40
|
Choice,
|
|
41
41
|
CompletionUsage,
|
|
42
42
|
NotGiven,
|
|
43
|
+
ParsedChatCompletion,
|
|
43
44
|
)
|
|
44
45
|
from .unified_model_type import UnifiedModelType
|
|
45
46
|
|
|
@@ -71,4 +72,5 @@ __all__ = [
|
|
|
71
72
|
'UnifiedModelType',
|
|
72
73
|
'NOT_GIVEN',
|
|
73
74
|
'NotGiven',
|
|
75
|
+
'ParsedChatCompletion',
|
|
74
76
|
]
|