camel-ai 0.1.1__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 +30 -0
- camel/agents/__init__.py +40 -0
- camel/agents/base.py +29 -0
- camel/agents/chat_agent.py +539 -0
- camel/agents/critic_agent.py +179 -0
- camel/agents/embodied_agent.py +138 -0
- camel/agents/role_assignment_agent.py +117 -0
- camel/agents/task_agent.py +382 -0
- camel/agents/tool_agents/__init__.py +20 -0
- camel/agents/tool_agents/base.py +40 -0
- camel/agents/tool_agents/hugging_face_tool_agent.py +203 -0
- camel/configs.py +159 -0
- camel/embeddings/__init__.py +20 -0
- camel/embeddings/base.py +65 -0
- camel/embeddings/openai_embedding.py +74 -0
- camel/functions/__init__.py +27 -0
- camel/functions/base_io_functions.py +261 -0
- camel/functions/math_functions.py +61 -0
- camel/functions/openai_function.py +88 -0
- camel/functions/search_functions.py +309 -0
- camel/functions/unstructured_io_fuctions.py +616 -0
- camel/functions/weather_functions.py +136 -0
- camel/generators.py +263 -0
- camel/human.py +130 -0
- camel/memories/__init__.py +28 -0
- camel/memories/base.py +75 -0
- camel/memories/chat_history_memory.py +111 -0
- camel/memories/context_creators/__init__.py +18 -0
- camel/memories/context_creators/base.py +72 -0
- camel/memories/context_creators/score_based.py +130 -0
- camel/memories/records.py +92 -0
- camel/messages/__init__.py +38 -0
- camel/messages/base.py +223 -0
- camel/messages/func_message.py +106 -0
- camel/models/__init__.py +26 -0
- camel/models/base_model.py +110 -0
- camel/models/model_factory.py +59 -0
- camel/models/open_source_model.py +144 -0
- camel/models/openai_model.py +103 -0
- camel/models/stub_model.py +106 -0
- camel/prompts/__init__.py +38 -0
- camel/prompts/ai_society.py +121 -0
- camel/prompts/base.py +227 -0
- camel/prompts/code.py +111 -0
- camel/prompts/evaluation.py +40 -0
- camel/prompts/misalignment.py +84 -0
- camel/prompts/prompt_templates.py +117 -0
- camel/prompts/role_description_prompt_template.py +53 -0
- camel/prompts/solution_extraction.py +44 -0
- camel/prompts/task_prompt_template.py +56 -0
- camel/prompts/translation.py +42 -0
- camel/responses/__init__.py +18 -0
- camel/responses/agent_responses.py +42 -0
- camel/societies/__init__.py +20 -0
- camel/societies/babyagi_playing.py +254 -0
- camel/societies/role_playing.py +456 -0
- camel/storages/__init__.py +23 -0
- camel/storages/key_value_storages/__init__.py +23 -0
- camel/storages/key_value_storages/base.py +57 -0
- camel/storages/key_value_storages/in_memory.py +51 -0
- camel/storages/key_value_storages/json.py +97 -0
- camel/terminators/__init__.py +23 -0
- camel/terminators/base.py +44 -0
- camel/terminators/response_terminator.py +118 -0
- camel/terminators/token_limit_terminator.py +55 -0
- camel/types/__init__.py +54 -0
- camel/types/enums.py +176 -0
- camel/types/openai_types.py +39 -0
- camel/utils/__init__.py +47 -0
- camel/utils/commons.py +243 -0
- camel/utils/python_interpreter.py +435 -0
- camel/utils/token_counting.py +220 -0
- camel_ai-0.1.1.dist-info/METADATA +311 -0
- camel_ai-0.1.1.dist-info/RECORD +75 -0
- camel_ai-0.1.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,88 @@
|
|
|
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 Any, Callable, Dict, Optional
|
|
15
|
+
|
|
16
|
+
from jsonschema.validators import Draft202012Validator as JSONValidator
|
|
17
|
+
|
|
18
|
+
from camel.utils import parse_doc
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OpenAIFunction:
|
|
22
|
+
r"""An abstraction of a function that OpenAI chat models can call. See
|
|
23
|
+
https://platform.openai.com/docs/guides/gpt/function-calling. If
|
|
24
|
+
:obj:`description` and :obj:`parameters` are both :obj:`None`, try to use
|
|
25
|
+
document parser to generate them.
|
|
26
|
+
|
|
27
|
+
# flake8: noqa :E501
|
|
28
|
+
Args:
|
|
29
|
+
func (Callable): The function to call.
|
|
30
|
+
name (str, optional): The name of the function to be called. Must be
|
|
31
|
+
a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum
|
|
32
|
+
length of 64. If :obj:`None`, use the name of :obj:`func`.
|
|
33
|
+
(default: :obj:`None`)
|
|
34
|
+
description (str, optional): The description of what the
|
|
35
|
+
function does. (default: :obj:`None`)
|
|
36
|
+
parameters (dict, optional): The parameters the
|
|
37
|
+
functions accepts, described as a JSON Schema object. See the
|
|
38
|
+
`Function calling guide <https://platform.openai.com/docs/guides/gpt/function-calling>`_
|
|
39
|
+
for examples, and the `JSON Schema reference <https://json-schema.org/understanding-json-schema/>`_
|
|
40
|
+
for documentation about the format.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, func: Callable, name: Optional[str] = None,
|
|
44
|
+
description: Optional[str] = None,
|
|
45
|
+
parameters: Optional[Dict[str, Any]] = None):
|
|
46
|
+
self.func = func
|
|
47
|
+
self.name = name or func.__name__
|
|
48
|
+
|
|
49
|
+
info = parse_doc(self.func)
|
|
50
|
+
self.description = description or info["description"]
|
|
51
|
+
self.parameters = parameters or info["parameters"]
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def parameters(self) -> Dict[str, Any]:
|
|
55
|
+
r"""Getter method for the property :obj:`parameters`.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Dict[str, Any]: the dictionary containing information of
|
|
59
|
+
parameters of this function.
|
|
60
|
+
"""
|
|
61
|
+
return self._parameters
|
|
62
|
+
|
|
63
|
+
@parameters.setter
|
|
64
|
+
def parameters(self, value: Dict[str, Any]):
|
|
65
|
+
r"""Setter method for the property :obj:`parameters`. It will
|
|
66
|
+
firstly check if the input parameters schema is valid. If invalid,
|
|
67
|
+
the method will raise :obj:`jsonschema.exceptions.SchemaError`.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
value (Dict[str, Any]): the new dictionary value for the
|
|
71
|
+
function's parameters.
|
|
72
|
+
"""
|
|
73
|
+
JSONValidator.check_schema(value)
|
|
74
|
+
self._parameters = value
|
|
75
|
+
|
|
76
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
77
|
+
r"""Method to represent the information of this function into
|
|
78
|
+
a dictionary object.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Dict[str, Any]: The dictionary object containing information
|
|
82
|
+
of this function's name, description and parameters.
|
|
83
|
+
"""
|
|
84
|
+
return {
|
|
85
|
+
attr: getattr(self, attr)
|
|
86
|
+
for attr in ["name", "description", "parameters"]
|
|
87
|
+
if getattr(self, attr) is not None
|
|
88
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
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 os
|
|
15
|
+
from typing import Any, Dict, List
|
|
16
|
+
|
|
17
|
+
import camel.agents
|
|
18
|
+
from camel.functions import OpenAIFunction
|
|
19
|
+
from camel.messages import BaseMessage
|
|
20
|
+
from camel.prompts import TextPrompt
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def search_wiki(entity: str) -> str:
|
|
24
|
+
r"""Search the entity in WikiPedia and return the summary of the
|
|
25
|
+
required page, containing factual information about the given entity.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
entity (string): The entity to be searched.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
string: The search result. If the page corresponding to the entity
|
|
32
|
+
exists, return the summary of this entity in a string.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
import wikipedia
|
|
36
|
+
except ImportError:
|
|
37
|
+
raise ImportError(
|
|
38
|
+
"Please install `wikipedia` first. You can install it by running "
|
|
39
|
+
"`pip install wikipedia`.")
|
|
40
|
+
|
|
41
|
+
result: str
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
result = wikipedia.summary(entity, sentences=5, auto_suggest=False)
|
|
45
|
+
except wikipedia.exceptions.DisambiguationError as e:
|
|
46
|
+
result = wikipedia.summary(e.options[0], sentences=5,
|
|
47
|
+
auto_suggest=False)
|
|
48
|
+
except wikipedia.exceptions.PageError:
|
|
49
|
+
result = ("There is no page in Wikipedia corresponding to entity "
|
|
50
|
+
f"{entity}, please specify another word to describe the"
|
|
51
|
+
" entity to be searched.")
|
|
52
|
+
except wikipedia.exceptions.WikipediaException as e:
|
|
53
|
+
result = f"An exception occurred during the search: {e}"
|
|
54
|
+
|
|
55
|
+
return result
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def search_google(query: str) -> List[Dict[str, Any]]:
|
|
59
|
+
r"""Use Google search engine to search information for the given query.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
query (string): The query to be searched.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
List[Dict[str, Any]]: A list of dictionaries where each dictionary
|
|
66
|
+
represents a website.
|
|
67
|
+
Each dictionary contains the following keys:
|
|
68
|
+
- 'result_id': A number in order.
|
|
69
|
+
- 'title': The title of the website.
|
|
70
|
+
- 'description': A brief description of the website.
|
|
71
|
+
- 'long_description': More detail of the website.
|
|
72
|
+
- 'url': The URL of the website.
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
{
|
|
76
|
+
'result_id': 1,
|
|
77
|
+
'title': 'OpenAI',
|
|
78
|
+
'description': 'An organization focused on ensuring that
|
|
79
|
+
artificial general intelligence benefits all of humanity.',
|
|
80
|
+
'long_description': 'OpenAI is a non-profit artificial
|
|
81
|
+
intelligence research company. Our goal is to advance digital
|
|
82
|
+
intelligence in the way that is most likely to benefit humanity
|
|
83
|
+
as a whole',
|
|
84
|
+
'url': 'https://www.openai.com'
|
|
85
|
+
}
|
|
86
|
+
title, descrption, url of a website.
|
|
87
|
+
"""
|
|
88
|
+
import requests
|
|
89
|
+
|
|
90
|
+
# https://developers.google.com/custom-search/v1/overview
|
|
91
|
+
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
|
92
|
+
# https://cse.google.com/cse/all
|
|
93
|
+
SEARCH_ENGINE_ID = os.getenv("SEARCH_ENGINE_ID")
|
|
94
|
+
|
|
95
|
+
# Using the first page
|
|
96
|
+
start_page_idx = 1
|
|
97
|
+
# Different language may get different result
|
|
98
|
+
search_language = "en"
|
|
99
|
+
# How many pages to return
|
|
100
|
+
num_result_pages = 10
|
|
101
|
+
# Constructing the URL
|
|
102
|
+
# Doc: https://developers.google.com/custom-search/v1/using_rest
|
|
103
|
+
url = f"https://www.googleapis.com/customsearch/v1?" \
|
|
104
|
+
f"key={GOOGLE_API_KEY}&cx={SEARCH_ENGINE_ID}&q={query}&start=" \
|
|
105
|
+
f"{start_page_idx}&lr={search_language}&num={num_result_pages}"
|
|
106
|
+
|
|
107
|
+
responses = []
|
|
108
|
+
# Fetch the results given the URL
|
|
109
|
+
try:
|
|
110
|
+
# Make the get
|
|
111
|
+
result = requests.get(url)
|
|
112
|
+
data = result.json()
|
|
113
|
+
|
|
114
|
+
# Get the result items
|
|
115
|
+
if "items" in data:
|
|
116
|
+
search_items = data.get("items")
|
|
117
|
+
|
|
118
|
+
# Iterate over 10 results found
|
|
119
|
+
for i, search_item in enumerate(search_items, start=1):
|
|
120
|
+
if "og:description" in search_item["pagemap"]["metatags"][0]:
|
|
121
|
+
long_description = \
|
|
122
|
+
search_item["pagemap"]["metatags"][0]["og:description"]
|
|
123
|
+
else:
|
|
124
|
+
long_description = "N/A"
|
|
125
|
+
# Get the page title
|
|
126
|
+
title = search_item.get("title")
|
|
127
|
+
# Page snippet
|
|
128
|
+
snippet = search_item.get("snippet")
|
|
129
|
+
|
|
130
|
+
# Extract the page url
|
|
131
|
+
link = search_item.get("link")
|
|
132
|
+
response = {
|
|
133
|
+
"result_id": i,
|
|
134
|
+
"title": title,
|
|
135
|
+
"description": snippet,
|
|
136
|
+
"long_description": long_description,
|
|
137
|
+
"url": link
|
|
138
|
+
}
|
|
139
|
+
responses.append(response)
|
|
140
|
+
else:
|
|
141
|
+
responses.append({"error": "google search failed."})
|
|
142
|
+
|
|
143
|
+
except requests.RequestException:
|
|
144
|
+
responses.append({"error": "google search failed."})
|
|
145
|
+
|
|
146
|
+
return responses
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def text_extract_from_web(url: str) -> str:
|
|
150
|
+
r"""Get the text information from given url.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
url (string): The web site you want to search.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
string: All texts extract from the web.
|
|
157
|
+
"""
|
|
158
|
+
import requests
|
|
159
|
+
from bs4 import BeautifulSoup
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
# Request the target page
|
|
163
|
+
response_text = requests.get(url).text
|
|
164
|
+
|
|
165
|
+
# Parse the obtained page
|
|
166
|
+
soup = BeautifulSoup(response_text, features="html.parser")
|
|
167
|
+
|
|
168
|
+
for script in soup(["script", "style"]):
|
|
169
|
+
script.extract()
|
|
170
|
+
|
|
171
|
+
text = soup.get_text()
|
|
172
|
+
# Strip text
|
|
173
|
+
lines = (line.strip() for line in text.splitlines())
|
|
174
|
+
chunks = (phrase.strip() for line in lines
|
|
175
|
+
for phrase in line.split(" "))
|
|
176
|
+
text = ".".join(chunk for chunk in chunks if chunk)
|
|
177
|
+
|
|
178
|
+
except requests.RequestException:
|
|
179
|
+
text = f"can't access {url}"
|
|
180
|
+
|
|
181
|
+
return text
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# Split a text into smaller chunks of size n
|
|
185
|
+
def create_chunks(text: str, n: int) -> List[str]:
|
|
186
|
+
r"""Returns successive n-sized chunks from provided text."
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
text (string): The text to be split.
|
|
190
|
+
n (int): The max length of a single chunk.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
List[str]: A list of splited texts.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
chunks = []
|
|
197
|
+
i = 0
|
|
198
|
+
while i < len(text):
|
|
199
|
+
# Find the nearest end of sentence within a range of 0.5 * n
|
|
200
|
+
# and 1.5 * n tokens
|
|
201
|
+
j = min(i + int(1.2 * n), len(text))
|
|
202
|
+
while j > i + int(0.8 * n):
|
|
203
|
+
# Decode the tokens and check for full stop or newline
|
|
204
|
+
chunk = text[i:j]
|
|
205
|
+
if chunk.endswith(".") or chunk.endswith("\n"):
|
|
206
|
+
break
|
|
207
|
+
j -= 1
|
|
208
|
+
# If no end of sentence found, use n tokens as the chunk size
|
|
209
|
+
if j == i + int(0.8 * n):
|
|
210
|
+
j = min(i + n, len(text))
|
|
211
|
+
chunks.append(text[i:j])
|
|
212
|
+
i = j
|
|
213
|
+
return chunks
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def prompt_single_step_agent(prompt: str) -> str:
|
|
217
|
+
"""Prompt a single-step agent to summarize texts or answer a question."""
|
|
218
|
+
|
|
219
|
+
assistant_sys_msg = BaseMessage.make_assistant_message(
|
|
220
|
+
role_name="Assistant",
|
|
221
|
+
content="You are a helpful assistant.",
|
|
222
|
+
)
|
|
223
|
+
agent = camel.agents.ChatAgent(assistant_sys_msg)
|
|
224
|
+
agent.reset()
|
|
225
|
+
|
|
226
|
+
user_msg = BaseMessage.make_user_message(
|
|
227
|
+
role_name="User",
|
|
228
|
+
content=prompt,
|
|
229
|
+
)
|
|
230
|
+
assistant_response = agent.step(user_msg)
|
|
231
|
+
if assistant_response.msgs is not None:
|
|
232
|
+
return assistant_response.msg.content
|
|
233
|
+
return ""
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def summarize_text(text: str, query: str) -> str:
|
|
237
|
+
r"""Summarize the information from the text, base on the query if query is
|
|
238
|
+
given.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
text (string): Text to summarise.
|
|
242
|
+
query (string): What information you want.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
string: Strings with information.
|
|
246
|
+
"""
|
|
247
|
+
summary_prompt = TextPrompt(
|
|
248
|
+
'''Gather information from this text that relative to the question, but
|
|
249
|
+
do not directly answer the question.\nquestion: {query}\ntext ''')
|
|
250
|
+
summary_prompt = summary_prompt.format(query=query)
|
|
251
|
+
# Max length of each chunk
|
|
252
|
+
max_len = 3000
|
|
253
|
+
results = ""
|
|
254
|
+
chunks = create_chunks(text, max_len)
|
|
255
|
+
# Summarize
|
|
256
|
+
for i, chunk in enumerate(chunks, start=1):
|
|
257
|
+
prompt = summary_prompt + str(i) + ": " + chunk
|
|
258
|
+
result = prompt_single_step_agent(prompt)
|
|
259
|
+
results += result + "\n"
|
|
260
|
+
|
|
261
|
+
# Final summarise
|
|
262
|
+
final_prompt = TextPrompt(
|
|
263
|
+
'''Here are some summarized texts which split from one text, Using the
|
|
264
|
+
information to answer the question: {query}.\n\nText: ''')
|
|
265
|
+
final_prompt = final_prompt.format(query=query)
|
|
266
|
+
prompt = final_prompt + results
|
|
267
|
+
|
|
268
|
+
response = prompt_single_step_agent(prompt)
|
|
269
|
+
|
|
270
|
+
return response
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def search_google_and_summarize(query: str) -> str:
|
|
274
|
+
r"""Search webs for information. Given a query, this function will use
|
|
275
|
+
the Google search engine to search for related information from the
|
|
276
|
+
internet, and then return a summarized answer.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
query (string): Question you want to be answered.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
string: Summarized information from webs.
|
|
283
|
+
"""
|
|
284
|
+
# Google search will return a list of urls
|
|
285
|
+
responses = search_google(query)
|
|
286
|
+
for item in responses:
|
|
287
|
+
if "url" in item:
|
|
288
|
+
url = item.get("url")
|
|
289
|
+
# Extract text
|
|
290
|
+
text = text_extract_from_web(str(url))
|
|
291
|
+
# Using chatgpt summarise text
|
|
292
|
+
answer = summarize_text(text, query)
|
|
293
|
+
|
|
294
|
+
# Let chatgpt decide whether to continue search or not
|
|
295
|
+
prompt = TextPrompt(
|
|
296
|
+
'''Do you think the answer: {answer} can answer the query:
|
|
297
|
+
{query}. Use only 'yes' or 'no' to answer.''')
|
|
298
|
+
prompt = prompt.format(answer=answer, query=query)
|
|
299
|
+
reply = prompt_single_step_agent(prompt)
|
|
300
|
+
if "yes" in str(reply).lower():
|
|
301
|
+
return answer
|
|
302
|
+
|
|
303
|
+
return "Failed to find the answer from google search."
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
SEARCH_FUNCS: List[OpenAIFunction] = [
|
|
307
|
+
OpenAIFunction(func)
|
|
308
|
+
for func in [search_wiki, search_google_and_summarize]
|
|
309
|
+
]
|