camel-ai 0.1.5.4__py3-none-any.whl → 0.1.5.5__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/configs/__init__.py +6 -0
- camel/configs/litellm_config.py +8 -18
- camel/configs/ollama_config.py +85 -0
- camel/configs/zhipuai_config.py +78 -0
- camel/embeddings/openai_embedding.py +2 -2
- camel/functions/search_functions.py +5 -14
- camel/functions/slack_functions.py +5 -7
- camel/functions/twitter_function.py +3 -8
- camel/functions/weather_functions.py +3 -8
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/docker_interpreter.py +235 -0
- camel/loaders/__init__.py +2 -0
- camel/loaders/base_io.py +5 -9
- camel/loaders/jina_url_reader.py +99 -0
- camel/loaders/unstructured_io.py +4 -6
- camel/models/anthropic_model.py +6 -4
- camel/models/litellm_model.py +49 -21
- camel/models/model_factory.py +1 -0
- camel/models/nemotron_model.py +14 -6
- camel/models/ollama_model.py +11 -17
- camel/models/openai_audio_models.py +10 -2
- camel/models/openai_model.py +4 -3
- camel/models/zhipuai_model.py +12 -6
- camel/retrievers/bm25_retriever.py +3 -8
- camel/retrievers/cohere_rerank_retriever.py +3 -5
- camel/storages/__init__.py +2 -0
- camel/storages/graph_storages/neo4j_graph.py +3 -7
- camel/storages/key_value_storages/__init__.py +2 -0
- camel/storages/key_value_storages/redis.py +169 -0
- camel/storages/vectordb_storages/milvus.py +3 -7
- camel/storages/vectordb_storages/qdrant.py +3 -7
- camel/toolkits/__init__.py +2 -0
- camel/toolkits/code_execution.py +69 -0
- camel/toolkits/github_toolkit.py +5 -9
- camel/types/enums.py +35 -1
- camel/utils/__init__.py +2 -2
- camel/utils/async_func.py +42 -0
- camel/utils/commons.py +31 -49
- camel/utils/token_counting.py +40 -1
- {camel_ai-0.1.5.4.dist-info → camel_ai-0.1.5.5.dist-info}/METADATA +11 -3
- {camel_ai-0.1.5.4.dist-info → camel_ai-0.1.5.5.dist-info}/RECORD +43 -36
- {camel_ai-0.1.5.4.dist-info → camel_ai-0.1.5.5.dist-info}/WHEEL +0 -0
|
@@ -16,6 +16,7 @@ from hashlib import md5
|
|
|
16
16
|
from typing import Any, Dict, List, Optional
|
|
17
17
|
|
|
18
18
|
from camel.storages.graph_storages import BaseGraphStorage, GraphElement
|
|
19
|
+
from camel.utils import dependencies_required
|
|
19
20
|
|
|
20
21
|
logger = logging.getLogger(__name__)
|
|
21
22
|
|
|
@@ -81,6 +82,7 @@ class Neo4jGraph(BaseGraphStorage):
|
|
|
81
82
|
than `LIST_LIMIT` elements from results. Defaults to `False`.
|
|
82
83
|
"""
|
|
83
84
|
|
|
85
|
+
@dependencies_required('neo4j')
|
|
84
86
|
def __init__(
|
|
85
87
|
self,
|
|
86
88
|
url: str,
|
|
@@ -91,13 +93,7 @@ class Neo4jGraph(BaseGraphStorage):
|
|
|
91
93
|
truncate: bool = False,
|
|
92
94
|
) -> None:
|
|
93
95
|
r"""Create a new Neo4j graph instance."""
|
|
94
|
-
|
|
95
|
-
import neo4j
|
|
96
|
-
except ImportError:
|
|
97
|
-
raise ValueError(
|
|
98
|
-
"Could not import neo4j python package. "
|
|
99
|
-
"Please install it with `pip install neo4j`."
|
|
100
|
-
)
|
|
96
|
+
import neo4j
|
|
101
97
|
|
|
102
98
|
self.driver = neo4j.GraphDatabase.driver(
|
|
103
99
|
url, auth=(username, password)
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
from .base import BaseKeyValueStorage
|
|
16
16
|
from .in_memory import InMemoryKeyValueStorage
|
|
17
17
|
from .json import JsonStorage
|
|
18
|
+
from .redis import RedisStorage
|
|
18
19
|
|
|
19
20
|
__all__ = [
|
|
20
21
|
'BaseKeyValueStorage',
|
|
21
22
|
'InMemoryKeyValueStorage',
|
|
22
23
|
'JsonStorage',
|
|
24
|
+
'RedisStorage',
|
|
23
25
|
]
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# =========== Copyright 2023 @ 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 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
19
|
+
|
|
20
|
+
from camel.storages.key_value_storages import BaseKeyValueStorage
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from redis.asyncio import Redis
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class RedisStorage(BaseKeyValueStorage):
|
|
29
|
+
r"""A concrete implementation of the :obj:`BaseCacheStorage` using Redis as
|
|
30
|
+
the backend. This is suitable for distributed cache systems that require
|
|
31
|
+
persistence and high availability.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
sid: str,
|
|
37
|
+
url: str = "redis://localhost:6379",
|
|
38
|
+
loop: Optional[asyncio.AbstractEventLoop] = None,
|
|
39
|
+
**kwargs,
|
|
40
|
+
) -> None:
|
|
41
|
+
r"""Initializes the RedisStorage instance with the provided URL and
|
|
42
|
+
options.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
sid (str): The ID for the storage instance to identify the
|
|
46
|
+
record space.
|
|
47
|
+
url (str): The URL for connecting to the Redis server.
|
|
48
|
+
**kwargs: Additional keyword arguments for Redis client
|
|
49
|
+
configuration.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ImportError: If the `redis.asyncio` module is not installed.
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
import redis.asyncio as aredis
|
|
56
|
+
except ImportError as exc:
|
|
57
|
+
logger.error(
|
|
58
|
+
"Please install `redis` first. You can install it by "
|
|
59
|
+
"running `pip install redis`."
|
|
60
|
+
)
|
|
61
|
+
raise exc
|
|
62
|
+
|
|
63
|
+
self._client: Optional[aredis.Redis] = None
|
|
64
|
+
self._url = url
|
|
65
|
+
self._sid = sid
|
|
66
|
+
self._loop = loop or asyncio.get_event_loop()
|
|
67
|
+
|
|
68
|
+
self._create_client(**kwargs)
|
|
69
|
+
|
|
70
|
+
def __enter__(self):
|
|
71
|
+
return self
|
|
72
|
+
|
|
73
|
+
def __exit__(self, exc_type, exc, tb):
|
|
74
|
+
self._run_async(self.close())
|
|
75
|
+
|
|
76
|
+
async def close(self) -> None:
|
|
77
|
+
r"""Closes the Redis client asynchronously."""
|
|
78
|
+
if self._client:
|
|
79
|
+
await self._client.close()
|
|
80
|
+
|
|
81
|
+
def _create_client(self, **kwargs) -> None:
|
|
82
|
+
r"""Creates the Redis client with the provided URL and options.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
**kwargs: Additional keyword arguments for Redis client
|
|
86
|
+
configuration.
|
|
87
|
+
"""
|
|
88
|
+
import redis.asyncio as aredis
|
|
89
|
+
|
|
90
|
+
self._client = aredis.from_url(self._url, **kwargs)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def client(self) -> Optional["Redis"]:
|
|
94
|
+
r"""Returns the Redis client instance.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
redis.asyncio.Redis: The Redis client instance.
|
|
98
|
+
"""
|
|
99
|
+
return self._client
|
|
100
|
+
|
|
101
|
+
def save(
|
|
102
|
+
self, records: List[Dict[str, Any]], expire: Optional[int] = None
|
|
103
|
+
) -> None:
|
|
104
|
+
r"""Saves a batch of records to the key-value storage system."""
|
|
105
|
+
try:
|
|
106
|
+
self._run_async(self._async_save(records, expire))
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.error(f"Error in save: {e}")
|
|
109
|
+
|
|
110
|
+
def load(self) -> List[Dict[str, Any]]:
|
|
111
|
+
r"""Loads all stored records from the key-value storage system.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List[Dict[str, Any]]: A list of dictionaries, where each dictionary
|
|
115
|
+
represents a stored record.
|
|
116
|
+
"""
|
|
117
|
+
try:
|
|
118
|
+
return self._run_async(self._async_load())
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"Error in load: {e}")
|
|
121
|
+
return []
|
|
122
|
+
|
|
123
|
+
def clear(self) -> None:
|
|
124
|
+
r"""Removes all records from the key-value storage system."""
|
|
125
|
+
try:
|
|
126
|
+
self._run_async(self._async_clear())
|
|
127
|
+
except Exception as e:
|
|
128
|
+
logger.error(f"Error in clear: {e}")
|
|
129
|
+
|
|
130
|
+
async def _async_save(
|
|
131
|
+
self, records: List[Dict[str, Any]], expire: Optional[int] = None
|
|
132
|
+
) -> None:
|
|
133
|
+
if self._client is None:
|
|
134
|
+
raise ValueError("Redis client is not initialized")
|
|
135
|
+
try:
|
|
136
|
+
value = json.dumps(records)
|
|
137
|
+
if expire:
|
|
138
|
+
await self._client.setex(self._sid, expire, value)
|
|
139
|
+
else:
|
|
140
|
+
await self._client.set(self._sid, value)
|
|
141
|
+
except Exception as e:
|
|
142
|
+
logger.error(f"Error saving records: {e}")
|
|
143
|
+
|
|
144
|
+
async def _async_load(self) -> List[Dict[str, Any]]:
|
|
145
|
+
if self._client is None:
|
|
146
|
+
raise ValueError("Redis client is not initialized")
|
|
147
|
+
try:
|
|
148
|
+
value = await self._client.get(self._sid)
|
|
149
|
+
if value:
|
|
150
|
+
return json.loads(value)
|
|
151
|
+
return []
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.error(f"Error loading records: {e}")
|
|
154
|
+
return []
|
|
155
|
+
|
|
156
|
+
async def _async_clear(self) -> None:
|
|
157
|
+
if self._client is None:
|
|
158
|
+
raise ValueError("Redis client is not initialized")
|
|
159
|
+
try:
|
|
160
|
+
await self._client.delete(self._sid)
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.error(f"Error clearing records: {e}")
|
|
163
|
+
|
|
164
|
+
def _run_async(self, coro):
|
|
165
|
+
if not self._loop.is_running():
|
|
166
|
+
return self._loop.run_until_complete(coro)
|
|
167
|
+
else:
|
|
168
|
+
future = asyncio.run_coroutine_threadsafe(coro, self._loop)
|
|
169
|
+
return future.result()
|
|
@@ -23,6 +23,7 @@ from camel.storages.vectordb_storages import (
|
|
|
23
23
|
VectorDBStatus,
|
|
24
24
|
VectorRecord,
|
|
25
25
|
)
|
|
26
|
+
from camel.utils import dependencies_required
|
|
26
27
|
|
|
27
28
|
logger = logging.getLogger(__name__)
|
|
28
29
|
|
|
@@ -52,6 +53,7 @@ class MilvusStorage(BaseVectorStorage):
|
|
|
52
53
|
ImportError: If `pymilvus` package is not installed.
|
|
53
54
|
"""
|
|
54
55
|
|
|
56
|
+
@dependencies_required('pymilvus')
|
|
55
57
|
def __init__(
|
|
56
58
|
self,
|
|
57
59
|
vector_dim: int,
|
|
@@ -59,13 +61,7 @@ class MilvusStorage(BaseVectorStorage):
|
|
|
59
61
|
collection_name: Optional[str] = None,
|
|
60
62
|
**kwargs: Any,
|
|
61
63
|
) -> None:
|
|
62
|
-
|
|
63
|
-
from pymilvus import MilvusClient
|
|
64
|
-
except ImportError as exc:
|
|
65
|
-
raise ImportError(
|
|
66
|
-
"Please install `pymilvus` first. You can install it by "
|
|
67
|
-
"running `pip install pymilvus`."
|
|
68
|
-
) from exc
|
|
64
|
+
from pymilvus import MilvusClient
|
|
69
65
|
|
|
70
66
|
self._client: MilvusClient
|
|
71
67
|
self._create_client(url_and_api_key, **kwargs)
|
|
@@ -23,6 +23,7 @@ from camel.storages.vectordb_storages import (
|
|
|
23
23
|
VectorRecord,
|
|
24
24
|
)
|
|
25
25
|
from camel.types import VectorDistance
|
|
26
|
+
from camel.utils import dependencies_required
|
|
26
27
|
|
|
27
28
|
_qdrant_local_client_map: Dict[str, Tuple[Any, int]] = {}
|
|
28
29
|
|
|
@@ -62,6 +63,7 @@ class QdrantStorage(BaseVectorStorage):
|
|
|
62
63
|
be initialized with an in-memory storage (`":memory:"`).
|
|
63
64
|
"""
|
|
64
65
|
|
|
66
|
+
@dependencies_required('qdrant_client')
|
|
65
67
|
def __init__(
|
|
66
68
|
self,
|
|
67
69
|
vector_dim: int,
|
|
@@ -72,13 +74,7 @@ class QdrantStorage(BaseVectorStorage):
|
|
|
72
74
|
delete_collection_on_del: bool = False,
|
|
73
75
|
**kwargs: Any,
|
|
74
76
|
) -> None:
|
|
75
|
-
|
|
76
|
-
from qdrant_client import QdrantClient
|
|
77
|
-
except ImportError as exc:
|
|
78
|
-
raise ImportError(
|
|
79
|
-
"Please install `qdrant-client` first. You can install it by "
|
|
80
|
-
"running `pip install qdrant-client`."
|
|
81
|
-
) from exc
|
|
77
|
+
from qdrant_client import QdrantClient
|
|
82
78
|
|
|
83
79
|
self._client: QdrantClient
|
|
84
80
|
self._local_path: Optional[str] = None
|
camel/toolkits/__init__.py
CHANGED
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
14
14
|
|
|
15
15
|
from .base import BaseToolkit
|
|
16
|
+
from .code_execution import CodeExecutionToolkit
|
|
16
17
|
from .github_toolkit import GithubToolkit
|
|
17
18
|
|
|
18
19
|
__all__ = [
|
|
19
20
|
'BaseToolkit',
|
|
20
21
|
'GithubToolkit',
|
|
22
|
+
'CodeExecutionToolkit',
|
|
21
23
|
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# =========== Copyright 2023 @ 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 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
14
|
+
from typing import List, Literal
|
|
15
|
+
|
|
16
|
+
from camel.functions import OpenAIFunction
|
|
17
|
+
from camel.interpreters import InternalPythonInterpreter
|
|
18
|
+
|
|
19
|
+
from .base import BaseToolkit
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CodeExecutionToolkit(BaseToolkit):
|
|
23
|
+
r"""A tookit for code execution.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
sandbox (str): the environment type used to execute code.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
sandbox: Literal[
|
|
32
|
+
"internal_python", "jupyter", "docker"
|
|
33
|
+
] = "internal_python",
|
|
34
|
+
verbose: bool = False,
|
|
35
|
+
) -> None:
|
|
36
|
+
# TODO: Add support for docker and jupyter.
|
|
37
|
+
self.verbose = verbose
|
|
38
|
+
if sandbox == "internal_python":
|
|
39
|
+
self.interpreter = InternalPythonInterpreter()
|
|
40
|
+
else:
|
|
41
|
+
raise RuntimeError(
|
|
42
|
+
f"The sandbox type `{sandbox}` is not supported."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def execute_code(self, code: str) -> str:
|
|
46
|
+
r"""Execute a given code snippet.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
code (str): The input code to the Code Interpreter tool call.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
str: The text output from the Code Interpreter tool call.
|
|
53
|
+
"""
|
|
54
|
+
output = self.interpreter.run(code, "python")
|
|
55
|
+
# ruff: noqa: E501
|
|
56
|
+
content = f"Executed the code below:\n```py\n{code}\n```\n> Executed Results:\n{output}"
|
|
57
|
+
if self.verbose:
|
|
58
|
+
print(content)
|
|
59
|
+
return content
|
|
60
|
+
|
|
61
|
+
def get_tools(self) -> List[OpenAIFunction]:
|
|
62
|
+
r"""Returns a list of OpenAIFunction objects representing the
|
|
63
|
+
functions in the toolkit.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
List[OpenAIFunction]: A list of OpenAIFunction objects
|
|
67
|
+
representing the functions in the toolkit.
|
|
68
|
+
"""
|
|
69
|
+
return [OpenAIFunction(self.execute_code)]
|
camel/toolkits/github_toolkit.py
CHANGED
|
@@ -18,8 +18,8 @@ from datetime import datetime, timedelta
|
|
|
18
18
|
from typing import List, Optional
|
|
19
19
|
|
|
20
20
|
from camel.functions import OpenAIFunction
|
|
21
|
-
|
|
22
|
-
from .
|
|
21
|
+
from camel.toolkits.base import BaseToolkit
|
|
22
|
+
from camel.utils import dependencies_required
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
@dataclass
|
|
@@ -130,6 +130,7 @@ class GithubToolkit(BaseToolkit):
|
|
|
130
130
|
`get_github_access_token` method.
|
|
131
131
|
"""
|
|
132
132
|
|
|
133
|
+
@dependencies_required('github')
|
|
133
134
|
def __init__(
|
|
134
135
|
self, repo_name: str, access_token: Optional[str] = None
|
|
135
136
|
) -> None:
|
|
@@ -144,13 +145,8 @@ class GithubToolkit(BaseToolkit):
|
|
|
144
145
|
if access_token is None:
|
|
145
146
|
access_token = self.get_github_access_token()
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
except ImportError:
|
|
150
|
-
raise ImportError(
|
|
151
|
-
"Please install `github` first. You can install it by running "
|
|
152
|
-
"`pip install pygithub`."
|
|
153
|
-
)
|
|
148
|
+
from github import Auth, Github
|
|
149
|
+
|
|
154
150
|
self.github = Github(auth=Auth.Token(access_token))
|
|
155
151
|
self.repo = self.github.get_repo(repo_name)
|
|
156
152
|
|
camel/types/enums.py
CHANGED
|
@@ -30,15 +30,19 @@ class ModelType(Enum):
|
|
|
30
30
|
GPT_4_TURBO = "gpt-4-turbo"
|
|
31
31
|
GPT_4O = "gpt-4o"
|
|
32
32
|
GLM_4 = "glm-4"
|
|
33
|
+
GLM_4_OPEN_SOURCE = "glm-4-open-source"
|
|
33
34
|
GLM_4V = 'glm-4v'
|
|
34
35
|
GLM_3_TURBO = "glm-3-turbo"
|
|
35
36
|
|
|
36
37
|
STUB = "stub"
|
|
37
38
|
|
|
38
39
|
LLAMA_2 = "llama-2"
|
|
40
|
+
LLAMA_3 = "llama-3"
|
|
39
41
|
VICUNA = "vicuna"
|
|
40
42
|
VICUNA_16K = "vicuna-16k"
|
|
41
43
|
|
|
44
|
+
QWEN_2 = "qwen-2"
|
|
45
|
+
|
|
42
46
|
# Legacy anthropic models
|
|
43
47
|
# NOTE: anthropic lagecy models only Claude 2.1 has system prompt support
|
|
44
48
|
CLAUDE_2_1 = "claude-2.1"
|
|
@@ -87,6 +91,9 @@ class ModelType(Enum):
|
|
|
87
91
|
r"""Returns whether this type of models is open-source."""
|
|
88
92
|
return self in {
|
|
89
93
|
ModelType.LLAMA_2,
|
|
94
|
+
ModelType.LLAMA_3,
|
|
95
|
+
ModelType.QWEN_2,
|
|
96
|
+
ModelType.GLM_4_OPEN_SOURCE,
|
|
90
97
|
ModelType.VICUNA,
|
|
91
98
|
ModelType.VICUNA_16K,
|
|
92
99
|
}
|
|
@@ -135,7 +142,7 @@ class ModelType(Enum):
|
|
|
135
142
|
return 128000
|
|
136
143
|
elif self is ModelType.GPT_4O:
|
|
137
144
|
return 128000
|
|
138
|
-
elif self == ModelType.
|
|
145
|
+
elif self == ModelType.GLM_4_OPEN_SOURCE:
|
|
139
146
|
return 8192
|
|
140
147
|
elif self == ModelType.GLM_3_TURBO:
|
|
141
148
|
return 8192
|
|
@@ -145,6 +152,12 @@ class ModelType(Enum):
|
|
|
145
152
|
return 4096
|
|
146
153
|
elif self is ModelType.LLAMA_2:
|
|
147
154
|
return 4096
|
|
155
|
+
elif self is ModelType.LLAMA_3:
|
|
156
|
+
return 8192
|
|
157
|
+
elif self is ModelType.QWEN_2:
|
|
158
|
+
return 128000
|
|
159
|
+
elif self is ModelType.GLM_4:
|
|
160
|
+
return 8192
|
|
148
161
|
elif self is ModelType.VICUNA:
|
|
149
162
|
# reference: https://lmsys.org/blog/2023-03-30-vicuna/
|
|
150
163
|
return 2048
|
|
@@ -184,6 +197,20 @@ class ModelType(Enum):
|
|
|
184
197
|
self.value in model_name.lower()
|
|
185
198
|
or "llama2" in model_name.lower()
|
|
186
199
|
)
|
|
200
|
+
elif self is ModelType.LLAMA_3:
|
|
201
|
+
return (
|
|
202
|
+
self.value in model_name.lower()
|
|
203
|
+
or "llama3" in model_name.lower()
|
|
204
|
+
)
|
|
205
|
+
elif self is ModelType.QWEN_2:
|
|
206
|
+
return (
|
|
207
|
+
self.value in model_name.lower()
|
|
208
|
+
or "qwen2" in model_name.lower()
|
|
209
|
+
)
|
|
210
|
+
elif self is ModelType.GLM_4_OPEN_SOURCE:
|
|
211
|
+
return (
|
|
212
|
+
'glm-4' in model_name.lower() or "glm4" in model_name.lower()
|
|
213
|
+
)
|
|
187
214
|
else:
|
|
188
215
|
return self.value in model_name.lower()
|
|
189
216
|
|
|
@@ -374,3 +401,10 @@ class VoiceType(Enum):
|
|
|
374
401
|
VoiceType.NOVA,
|
|
375
402
|
VoiceType.SHIMMER,
|
|
376
403
|
}
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class JinaReturnFormat(Enum):
|
|
407
|
+
DEFAULT = None
|
|
408
|
+
MARKDOWN = "markdown"
|
|
409
|
+
HTML = "html"
|
|
410
|
+
TEXT = "text"
|
camel/utils/__init__.py
CHANGED
|
@@ -23,7 +23,7 @@ from .commons import (
|
|
|
23
23
|
get_prompt_template_key_words,
|
|
24
24
|
get_system_information,
|
|
25
25
|
get_task_list,
|
|
26
|
-
|
|
26
|
+
is_docker_running,
|
|
27
27
|
print_text_animated,
|
|
28
28
|
text_extract_from_web,
|
|
29
29
|
to_pascal,
|
|
@@ -39,7 +39,6 @@ from .token_counting import (
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
__all__ = [
|
|
42
|
-
'model_api_key_required',
|
|
43
42
|
'print_text_animated',
|
|
44
43
|
'get_prompt_template_key_words',
|
|
45
44
|
'get_first_int',
|
|
@@ -60,4 +59,5 @@ __all__ = [
|
|
|
60
59
|
'create_chunks',
|
|
61
60
|
'dependencies_required',
|
|
62
61
|
'api_keys_required',
|
|
62
|
+
'is_docker_running',
|
|
63
63
|
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# =========== Copyright 2023 @ 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 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
14
|
+
import asyncio
|
|
15
|
+
from copy import deepcopy
|
|
16
|
+
|
|
17
|
+
from camel.functions.openai_function import OpenAIFunction
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def sync_funcs_to_async(funcs: list[OpenAIFunction]) -> list[OpenAIFunction]:
|
|
21
|
+
r"""Convert a list of Python synchronous functions to Python
|
|
22
|
+
asynchronous functions.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
funcs (list[OpenAIFunction]): List of Python synchronous
|
|
26
|
+
functions in the :obj:`OpenAIFunction` format.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
list[OpenAIFunction]: List of Python asynchronous functions
|
|
30
|
+
in the :obj:`OpenAIFunction` format.
|
|
31
|
+
"""
|
|
32
|
+
async_funcs = []
|
|
33
|
+
for func in funcs:
|
|
34
|
+
sync_func = func.func
|
|
35
|
+
|
|
36
|
+
def async_callable(*args, **kwargs):
|
|
37
|
+
return asyncio.to_thread(sync_func, *args, **kwargs) # noqa: B023
|
|
38
|
+
|
|
39
|
+
async_funcs.append(
|
|
40
|
+
OpenAIFunction(async_callable, deepcopy(func.openai_tool_schema))
|
|
41
|
+
)
|
|
42
|
+
return async_funcs
|
camel/utils/commons.py
CHANGED
|
@@ -16,6 +16,7 @@ import os
|
|
|
16
16
|
import platform
|
|
17
17
|
import re
|
|
18
18
|
import socket
|
|
19
|
+
import subprocess
|
|
19
20
|
import time
|
|
20
21
|
import zipfile
|
|
21
22
|
from functools import wraps
|
|
@@ -30,48 +31,6 @@ from camel.types import TaskType
|
|
|
30
31
|
F = TypeVar('F', bound=Callable[..., Any])
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
def model_api_key_required(func: F) -> F:
|
|
34
|
-
r"""Decorator that checks if the API key is available either as an
|
|
35
|
-
environment variable or passed directly for a model.
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
func (callable): The function to be wrapped.
|
|
39
|
-
|
|
40
|
-
Returns:
|
|
41
|
-
callable: The decorated function.
|
|
42
|
-
|
|
43
|
-
Raises:
|
|
44
|
-
ValueError: If the API key is not found, either as an environment
|
|
45
|
-
variable or directly passed.
|
|
46
|
-
|
|
47
|
-
Note:
|
|
48
|
-
Supported model type: `OpenAI` and `Anthropic`.
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
@wraps(func)
|
|
52
|
-
def wrapper(self, *args, **kwargs):
|
|
53
|
-
if self.model_type.is_openai:
|
|
54
|
-
if not self._api_key and 'OPENAI_API_KEY' not in os.environ:
|
|
55
|
-
raise ValueError('OpenAI API key not found.')
|
|
56
|
-
return func(self, *args, **kwargs)
|
|
57
|
-
elif self.model_type.is_zhipuai:
|
|
58
|
-
if 'ZHIPUAI_API_KEY' not in os.environ:
|
|
59
|
-
raise ValueError('ZhiPuAI API key not found.')
|
|
60
|
-
return func(self, *args, **kwargs)
|
|
61
|
-
elif self.model_type.is_anthropic:
|
|
62
|
-
if not self._api_key and 'ANTHROPIC_API_KEY' not in os.environ:
|
|
63
|
-
raise ValueError('Anthropic API key not found.')
|
|
64
|
-
return func(self, *args, **kwargs)
|
|
65
|
-
elif self.model_type.is_nvidia:
|
|
66
|
-
if not self._api_key and 'NVIDIA_API_KEY' not in os.environ:
|
|
67
|
-
raise ValueError('NVIDIA API key not found.')
|
|
68
|
-
return func(self, *args, **kwargs)
|
|
69
|
-
else:
|
|
70
|
-
raise ValueError('Unsupported model type.')
|
|
71
|
-
|
|
72
|
-
return cast(F, wrapper)
|
|
73
|
-
|
|
74
|
-
|
|
75
34
|
def print_text_animated(text, delay: float = 0.02, end: str = ""):
|
|
76
35
|
r"""Prints the given text with an animated effect.
|
|
77
36
|
|
|
@@ -260,7 +219,7 @@ def is_module_available(module_name: str) -> bool:
|
|
|
260
219
|
|
|
261
220
|
def api_keys_required(*required_keys: str) -> Callable[[F], F]:
|
|
262
221
|
r"""A decorator to check if the required API keys are
|
|
263
|
-
|
|
222
|
+
presented in the environment variables or as an instance attribute.
|
|
264
223
|
|
|
265
224
|
Args:
|
|
266
225
|
required_keys (str): The required API keys to be checked.
|
|
@@ -271,7 +230,7 @@ def api_keys_required(*required_keys: str) -> Callable[[F], F]:
|
|
|
271
230
|
|
|
272
231
|
Raises:
|
|
273
232
|
ValueError: If any of the required API keys are missing in the
|
|
274
|
-
environment variables.
|
|
233
|
+
environment variables and the instance attribute.
|
|
275
234
|
|
|
276
235
|
Example:
|
|
277
236
|
::
|
|
@@ -283,13 +242,18 @@ def api_keys_required(*required_keys: str) -> Callable[[F], F]:
|
|
|
283
242
|
|
|
284
243
|
def decorator(func: F) -> F:
|
|
285
244
|
@wraps(func)
|
|
286
|
-
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
287
|
-
|
|
288
|
-
|
|
245
|
+
def wrapper(self, *args: Any, **kwargs: Any) -> Any:
|
|
246
|
+
missing_environment_keys = [
|
|
247
|
+
k for k in required_keys if k not in os.environ
|
|
248
|
+
]
|
|
249
|
+
if (
|
|
250
|
+
not getattr(self, '_api_key', None)
|
|
251
|
+
and missing_environment_keys
|
|
252
|
+
):
|
|
289
253
|
raise ValueError(
|
|
290
|
-
f"Missing API keys: {', '.join(
|
|
254
|
+
f"Missing API keys: {', '.join(missing_environment_keys)}"
|
|
291
255
|
)
|
|
292
|
-
return func(*args, **kwargs)
|
|
256
|
+
return func(self, *args, **kwargs)
|
|
293
257
|
|
|
294
258
|
return cast(F, wrapper)
|
|
295
259
|
|
|
@@ -400,3 +364,21 @@ def create_chunks(text: str, n: int) -> List[str]:
|
|
|
400
364
|
chunks.append(text[i:j])
|
|
401
365
|
i = j
|
|
402
366
|
return chunks
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def is_docker_running() -> bool:
|
|
370
|
+
r"""Check if the Docker daemon is running.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
bool: True if the Docker daemon is running, False otherwise.
|
|
374
|
+
"""
|
|
375
|
+
try:
|
|
376
|
+
result = subprocess.run(
|
|
377
|
+
["docker", "info"],
|
|
378
|
+
check=True,
|
|
379
|
+
stdout=subprocess.PIPE,
|
|
380
|
+
stderr=subprocess.PIPE,
|
|
381
|
+
)
|
|
382
|
+
return result.returncode == 0
|
|
383
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
384
|
+
return False
|