camel-ai 0.2.3__py3-none-any.whl → 0.2.3a0__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/agents/chat_agent.py +69 -93
- camel/agents/knowledge_graph_agent.py +6 -4
- camel/bots/__init__.py +2 -16
- camel/bots/discord_bot.py +206 -0
- camel/configs/__init__.py +2 -1
- camel/configs/anthropic_config.py +5 -2
- camel/configs/base_config.py +6 -6
- camel/configs/groq_config.py +3 -2
- camel/configs/ollama_config.py +2 -1
- camel/configs/openai_config.py +23 -2
- camel/configs/samba_config.py +2 -2
- camel/configs/togetherai_config.py +1 -1
- camel/configs/vllm_config.py +1 -1
- camel/configs/zhipuai_config.py +3 -2
- camel/embeddings/openai_embedding.py +2 -2
- camel/loaders/__init__.py +0 -2
- camel/loaders/firecrawl_reader.py +3 -3
- camel/loaders/unstructured_io.py +33 -35
- camel/messages/__init__.py +0 -1
- camel/models/__init__.py +4 -2
- camel/models/anthropic_model.py +26 -32
- camel/models/azure_openai_model.py +36 -39
- camel/models/base_model.py +20 -31
- camel/models/gemini_model.py +29 -37
- camel/models/groq_model.py +23 -29
- camel/models/litellm_model.py +61 -44
- camel/models/mistral_model.py +29 -32
- camel/models/model_factory.py +76 -66
- camel/models/nemotron_model.py +23 -33
- camel/models/ollama_model.py +47 -42
- camel/models/open_source_model.py +170 -0
- camel/models/{openai_compatible_model.py → openai_compatibility_model.py} +49 -31
- camel/models/openai_model.py +29 -48
- camel/models/reka_model.py +28 -30
- camel/models/samba_model.py +177 -82
- camel/models/stub_model.py +2 -2
- camel/models/togetherai_model.py +43 -37
- camel/models/vllm_model.py +50 -43
- camel/models/zhipuai_model.py +27 -33
- camel/retrievers/auto_retriever.py +10 -28
- camel/retrievers/vector_retriever.py +47 -58
- camel/societies/babyagi_playing.py +3 -6
- camel/societies/role_playing.py +3 -5
- camel/storages/graph_storages/graph_element.py +5 -3
- camel/storages/key_value_storages/json.py +1 -6
- camel/toolkits/__init__.py +7 -20
- camel/toolkits/base.py +3 -2
- camel/toolkits/code_execution.py +7 -6
- camel/toolkits/dalle_toolkit.py +6 -6
- camel/toolkits/github_toolkit.py +10 -9
- camel/toolkits/google_maps_toolkit.py +7 -7
- camel/toolkits/linkedin_toolkit.py +7 -7
- camel/toolkits/math_toolkit.py +8 -8
- camel/toolkits/open_api_toolkit.py +5 -5
- camel/toolkits/{function_tool.py → openai_function.py} +11 -34
- camel/toolkits/reddit_toolkit.py +7 -7
- camel/toolkits/retrieval_toolkit.py +5 -5
- camel/toolkits/search_toolkit.py +9 -9
- camel/toolkits/slack_toolkit.py +11 -11
- camel/toolkits/twitter_toolkit.py +452 -378
- camel/toolkits/weather_toolkit.py +6 -6
- camel/types/__init__.py +1 -6
- camel/types/enums.py +85 -40
- camel/types/openai_types.py +0 -3
- camel/utils/__init__.py +2 -0
- camel/utils/async_func.py +7 -7
- camel/utils/commons.py +3 -32
- camel/utils/token_counting.py +212 -30
- camel/workforce/role_playing_worker.py +1 -1
- camel/workforce/single_agent_worker.py +1 -1
- camel/workforce/task_channel.py +3 -4
- camel/workforce/workforce.py +4 -4
- {camel_ai-0.2.3.dist-info → camel_ai-0.2.3a0.dist-info}/METADATA +56 -27
- {camel_ai-0.2.3.dist-info → camel_ai-0.2.3a0.dist-info}/RECORD +76 -85
- {camel_ai-0.2.3.dist-info → camel_ai-0.2.3a0.dist-info}/WHEEL +1 -1
- camel/bots/discord_app.py +0 -138
- camel/bots/slack/__init__.py +0 -30
- camel/bots/slack/models.py +0 -158
- camel/bots/slack/slack_app.py +0 -255
- camel/loaders/chunkr_reader.py +0 -163
- camel/toolkits/arxiv_toolkit.py +0 -155
- camel/toolkits/ask_news_toolkit.py +0 -653
- camel/toolkits/google_scholar_toolkit.py +0 -146
- camel/toolkits/whatsapp_toolkit.py +0 -177
- camel/types/unified_model_type.py +0 -104
- camel_ai-0.2.3.dist-info/LICENSE +0 -201
camel/models/samba_model.py
CHANGED
|
@@ -22,11 +22,10 @@ from openai import OpenAI, Stream
|
|
|
22
22
|
|
|
23
23
|
from camel.configs import (
|
|
24
24
|
SAMBA_CLOUD_API_PARAMS,
|
|
25
|
+
SAMBA_FAST_API_PARAMS,
|
|
25
26
|
SAMBA_VERSE_API_PARAMS,
|
|
26
|
-
SambaCloudAPIConfig,
|
|
27
27
|
)
|
|
28
28
|
from camel.messages import OpenAIMessage
|
|
29
|
-
from camel.models import BaseModelBackend
|
|
30
29
|
from camel.types import (
|
|
31
30
|
ChatCompletion,
|
|
32
31
|
ChatCompletionChunk,
|
|
@@ -39,59 +38,48 @@ from camel.utils import (
|
|
|
39
38
|
api_keys_required,
|
|
40
39
|
)
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
else:
|
|
46
|
-
raise ImportError
|
|
47
|
-
except (ImportError, AttributeError):
|
|
48
|
-
LLMEvent = None
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class SambaModel(BaseModelBackend):
|
|
52
|
-
r"""SambaNova service interface.
|
|
53
|
-
|
|
54
|
-
Args:
|
|
55
|
-
model_type (Union[ModelType, str]): Model for which a SambaNova backend
|
|
56
|
-
is created. Supported models via SambaNova Cloud:
|
|
57
|
-
`https://community.sambanova.ai/t/supported-models/193`.
|
|
58
|
-
Supported models via SambaVerse API is listed in
|
|
59
|
-
`https://sambaverse.sambanova.ai/models`.
|
|
60
|
-
model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
|
|
61
|
-
that will be fed into:obj:`openai.ChatCompletion.create()`. If
|
|
62
|
-
:obj:`None`, :obj:`SambaCloudAPIConfig().as_dict()` will be used.
|
|
63
|
-
(default: :obj:`None`)
|
|
64
|
-
api_key (Optional[str], optional): The API key for authenticating
|
|
65
|
-
with the SambaNova service. (default: :obj:`None`)
|
|
66
|
-
url (Optional[str], optional): The url to the SambaNova service.
|
|
67
|
-
Current support SambaVerse API:
|
|
68
|
-
:obj:`"https://sambaverse.sambanova.ai/api/predict"` and
|
|
69
|
-
SambaNova Cloud:
|
|
70
|
-
:obj:`"https://api.sambanova.ai/v1"` (default: :obj:`https://api.
|
|
71
|
-
sambanova.ai/v1`)
|
|
72
|
-
token_counter (Optional[BaseTokenCounter], optional): Token counter to
|
|
73
|
-
use for the model. If not provided, :obj:`OpenAITokenCounter(
|
|
74
|
-
ModelType.GPT_4O_MINI)` will be used.
|
|
75
|
-
"""
|
|
41
|
+
|
|
42
|
+
class SambaModel:
|
|
43
|
+
r"""SambaNova service interface."""
|
|
76
44
|
|
|
77
45
|
def __init__(
|
|
78
46
|
self,
|
|
79
|
-
model_type:
|
|
80
|
-
model_config_dict:
|
|
47
|
+
model_type: str,
|
|
48
|
+
model_config_dict: Dict[str, Any],
|
|
81
49
|
api_key: Optional[str] = None,
|
|
82
50
|
url: Optional[str] = None,
|
|
83
51
|
token_counter: Optional[BaseTokenCounter] = None,
|
|
84
52
|
) -> None:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
53
|
+
r"""Constructor for SambaNova backend.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
model_type (str): Model for which a SambaNova backend is
|
|
57
|
+
created. Supported models via Fast API: `https://sambanova.ai/
|
|
58
|
+
fast-api?api_ref=128521`. Supported models via SambaVerse API
|
|
59
|
+
is listed in `https://sambaverse.sambanova.ai/models`.
|
|
60
|
+
model_config_dict (Dict[str, Any]): A dictionary that will
|
|
61
|
+
be fed into API request.
|
|
62
|
+
api_key (Optional[str]): The API key for authenticating with the
|
|
63
|
+
SambaNova service. (default: :obj:`None`)
|
|
64
|
+
url (Optional[str]): The url to the SambaNova service. Current
|
|
65
|
+
support SambaNova Fast API: :obj:`"https://fast-api.snova.ai/
|
|
66
|
+
v1/chat/ completions"`, SambaVerse API: :obj:`"https://
|
|
67
|
+
sambaverse.sambanova.ai/api/predict"` and SambaNova Cloud:
|
|
68
|
+
:obj:`"https://api.sambanova.ai/v1"`
|
|
69
|
+
(default::obj:`"https://fast-api.snova.ai/v1/chat/completions"`)
|
|
70
|
+
token_counter (Optional[BaseTokenCounter]): Token counter to use
|
|
71
|
+
for the model. If not provided, `OpenAITokenCounter(ModelType.
|
|
72
|
+
GPT_4O_MINI)` will be used.
|
|
73
|
+
"""
|
|
74
|
+
self.model_type = model_type
|
|
75
|
+
self._api_key = api_key or os.environ.get("SAMBA_API_KEY")
|
|
76
|
+
self._url = url or os.environ.get(
|
|
89
77
|
"SAMBA_API_BASE_URL",
|
|
90
|
-
"https://api.
|
|
91
|
-
)
|
|
92
|
-
super().__init__(
|
|
93
|
-
model_type, model_config_dict, api_key, url, token_counter
|
|
78
|
+
"https://fast-api.snova.ai/v1/chat/completions",
|
|
94
79
|
)
|
|
80
|
+
self._token_counter = token_counter
|
|
81
|
+
self.model_config_dict = model_config_dict
|
|
82
|
+
self.check_model_config()
|
|
95
83
|
|
|
96
84
|
if self._url == "https://api.sambanova.ai/v1":
|
|
97
85
|
self._client = OpenAI(
|
|
@@ -121,7 +109,14 @@ class SambaModel(BaseModelBackend):
|
|
|
121
109
|
ValueError: If the model configuration dictionary contains any
|
|
122
110
|
unexpected arguments to SambaNova API.
|
|
123
111
|
"""
|
|
124
|
-
if self._url == "https://
|
|
112
|
+
if self._url == "https://fast-api.snova.ai/v1/chat/completions":
|
|
113
|
+
for param in self.model_config_dict:
|
|
114
|
+
if param not in SAMBA_FAST_API_PARAMS:
|
|
115
|
+
raise ValueError(
|
|
116
|
+
f"Unexpected argument `{param}` is "
|
|
117
|
+
"input into SambaNova Fast API."
|
|
118
|
+
)
|
|
119
|
+
elif self._url == "https://sambaverse.sambanova.ai/api/predict":
|
|
125
120
|
for param in self.model_config_dict:
|
|
126
121
|
if param not in SAMBA_VERSE_API_PARAMS:
|
|
127
122
|
raise ValueError(
|
|
@@ -164,7 +159,7 @@ class SambaModel(BaseModelBackend):
|
|
|
164
159
|
else:
|
|
165
160
|
return self._run_non_streaming(messages)
|
|
166
161
|
|
|
167
|
-
def _run_streaming(
|
|
162
|
+
def _run_streaming( # type: ignore[misc]
|
|
168
163
|
self, messages: List[OpenAIMessage]
|
|
169
164
|
) -> Stream[ChatCompletionChunk]:
|
|
170
165
|
r"""Handles streaming inference with SambaNova's API.
|
|
@@ -180,30 +175,48 @@ class SambaModel(BaseModelBackend):
|
|
|
180
175
|
|
|
181
176
|
Raises:
|
|
182
177
|
RuntimeError: If the HTTP request fails.
|
|
183
|
-
ValueError: If the API doesn't support stream mode.
|
|
184
178
|
"""
|
|
179
|
+
|
|
180
|
+
# Handle SambaNova's Fast API
|
|
181
|
+
if self._url == "https://fast-api.snova.ai/v1/chat/completions":
|
|
182
|
+
headers = {
|
|
183
|
+
"Authorization": f"Basic {self._api_key}",
|
|
184
|
+
"Content-Type": "application/json",
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
data = {
|
|
188
|
+
"messages": messages,
|
|
189
|
+
"max_tokens": self.token_limit,
|
|
190
|
+
"stop": self.model_config_dict.get("stop"),
|
|
191
|
+
"model": self.model_type,
|
|
192
|
+
"stream": True,
|
|
193
|
+
"stream_options": self.model_config_dict.get("stream_options"),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
with httpx.stream(
|
|
198
|
+
"POST",
|
|
199
|
+
self._url,
|
|
200
|
+
headers=headers,
|
|
201
|
+
json=data,
|
|
202
|
+
) as api_response:
|
|
203
|
+
stream = Stream[ChatCompletionChunk](
|
|
204
|
+
cast_to=ChatCompletionChunk,
|
|
205
|
+
response=api_response,
|
|
206
|
+
client=OpenAI(api_key="required_but_not_used"),
|
|
207
|
+
)
|
|
208
|
+
for chunk in stream:
|
|
209
|
+
yield chunk
|
|
210
|
+
except httpx.HTTPError as e:
|
|
211
|
+
raise RuntimeError(f"HTTP request failed: {e!s}")
|
|
212
|
+
|
|
185
213
|
# Handle SambaNova's Cloud API
|
|
186
|
-
|
|
214
|
+
elif self._url == "https://api.sambanova.ai/v1":
|
|
187
215
|
response = self._client.chat.completions.create(
|
|
188
216
|
messages=messages,
|
|
189
217
|
model=self.model_type,
|
|
190
218
|
**self.model_config_dict,
|
|
191
219
|
)
|
|
192
|
-
|
|
193
|
-
# Add AgentOps LLM Event tracking
|
|
194
|
-
if LLMEvent:
|
|
195
|
-
llm_event = LLMEvent(
|
|
196
|
-
thread_id=response.id,
|
|
197
|
-
prompt=" ".join(
|
|
198
|
-
[message.get("content") for message in messages] # type: ignore[misc]
|
|
199
|
-
),
|
|
200
|
-
prompt_tokens=response.usage.prompt_tokens, # type: ignore[union-attr]
|
|
201
|
-
completion=response.choices[0].message.content,
|
|
202
|
-
completion_tokens=response.usage.completion_tokens, # type: ignore[union-attr]
|
|
203
|
-
model=self.model_type,
|
|
204
|
-
)
|
|
205
|
-
record(llm_event)
|
|
206
|
-
|
|
207
220
|
return response
|
|
208
221
|
|
|
209
222
|
elif self._url == "https://sambaverse.sambanova.ai/api/predict":
|
|
@@ -211,7 +224,6 @@ class SambaModel(BaseModelBackend):
|
|
|
211
224
|
"https://sambaverse.sambanova.ai/api/predict doesn't support"
|
|
212
225
|
" stream mode"
|
|
213
226
|
)
|
|
214
|
-
raise RuntimeError(f"Unknown URL: {self._url}")
|
|
215
227
|
|
|
216
228
|
def _run_non_streaming(
|
|
217
229
|
self, messages: List[OpenAIMessage]
|
|
@@ -231,28 +243,51 @@ class SambaModel(BaseModelBackend):
|
|
|
231
243
|
ValueError: If the JSON response cannot be decoded or is missing
|
|
232
244
|
expected data.
|
|
233
245
|
"""
|
|
246
|
+
|
|
247
|
+
# Handle SambaNova's Fast API
|
|
248
|
+
if self._url == "https://fast-api.snova.ai/v1/chat/completions":
|
|
249
|
+
headers = {
|
|
250
|
+
"Authorization": f"Basic {self._api_key}",
|
|
251
|
+
"Content-Type": "application/json",
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
data = {
|
|
255
|
+
"messages": messages,
|
|
256
|
+
"max_tokens": self.token_limit,
|
|
257
|
+
"stop": self.model_config_dict.get("stop"),
|
|
258
|
+
"model": self.model_type,
|
|
259
|
+
"stream": True,
|
|
260
|
+
"stream_options": self.model_config_dict.get("stream_options"),
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
with httpx.stream(
|
|
265
|
+
"POST",
|
|
266
|
+
self._url,
|
|
267
|
+
headers=headers,
|
|
268
|
+
json=data,
|
|
269
|
+
) as api_response:
|
|
270
|
+
samba_response = []
|
|
271
|
+
for chunk in api_response.iter_text():
|
|
272
|
+
if chunk.startswith('data: '):
|
|
273
|
+
chunk = chunk[6:]
|
|
274
|
+
if '[DONE]' in chunk:
|
|
275
|
+
break
|
|
276
|
+
json_data = json.loads(chunk)
|
|
277
|
+
samba_response.append(json_data)
|
|
278
|
+
return self._fastapi_to_openai_response(samba_response)
|
|
279
|
+
except httpx.HTTPError as e:
|
|
280
|
+
raise RuntimeError(f"HTTP request failed: {e!s}")
|
|
281
|
+
except json.JSONDecodeError as e:
|
|
282
|
+
raise ValueError(f"Failed to decode JSON response: {e!s}")
|
|
283
|
+
|
|
234
284
|
# Handle SambaNova's Cloud API
|
|
235
|
-
|
|
285
|
+
elif self._url == "https://api.sambanova.ai/v1":
|
|
236
286
|
response = self._client.chat.completions.create(
|
|
237
287
|
messages=messages,
|
|
238
288
|
model=self.model_type,
|
|
239
289
|
**self.model_config_dict,
|
|
240
290
|
)
|
|
241
|
-
|
|
242
|
-
# Add AgentOps LLM Event tracking
|
|
243
|
-
if LLMEvent:
|
|
244
|
-
llm_event = LLMEvent(
|
|
245
|
-
thread_id=response.id,
|
|
246
|
-
prompt=" ".join(
|
|
247
|
-
[message.get("content") for message in messages] # type: ignore[misc]
|
|
248
|
-
),
|
|
249
|
-
prompt_tokens=response.usage.prompt_tokens, # type: ignore[union-attr]
|
|
250
|
-
completion=response.choices[0].message.content,
|
|
251
|
-
completion_tokens=response.usage.completion_tokens, # type: ignore[union-attr]
|
|
252
|
-
model=self.model_type,
|
|
253
|
-
)
|
|
254
|
-
record(llm_event)
|
|
255
|
-
|
|
256
291
|
return response
|
|
257
292
|
|
|
258
293
|
# Handle SambaNova's Sambaverse API
|
|
@@ -335,6 +370,56 @@ class SambaModel(BaseModelBackend):
|
|
|
335
370
|
except httpx.HTTPStatusError:
|
|
336
371
|
raise RuntimeError(f"HTTP request failed: {raw_text}")
|
|
337
372
|
|
|
373
|
+
def _fastapi_to_openai_response(
|
|
374
|
+
self, samba_response: List[Dict[str, Any]]
|
|
375
|
+
) -> ChatCompletion:
|
|
376
|
+
r"""Converts SambaNova Fast API response chunks into an
|
|
377
|
+
OpenAI-compatible response.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
samba_response (List[Dict[str, Any]]): A list of dictionaries
|
|
381
|
+
representing partial responses from the SambaNova Fast API.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
ChatCompletion: A `ChatCompletion` object constructed from the
|
|
385
|
+
aggregated response data.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
# Step 1: Combine the content from each chunk
|
|
389
|
+
full_content = ""
|
|
390
|
+
for chunk in samba_response:
|
|
391
|
+
if chunk['choices']:
|
|
392
|
+
for choice in chunk['choices']:
|
|
393
|
+
delta_content = choice['delta'].get('content', '')
|
|
394
|
+
full_content += delta_content
|
|
395
|
+
|
|
396
|
+
# Step 2: Create the ChatCompletion object
|
|
397
|
+
# Extract relevant information from the first chunk
|
|
398
|
+
first_chunk = samba_response[0]
|
|
399
|
+
|
|
400
|
+
choices = [
|
|
401
|
+
dict(
|
|
402
|
+
index=0, # type: ignore[index]
|
|
403
|
+
message={
|
|
404
|
+
"role": 'assistant',
|
|
405
|
+
"content": full_content.strip(),
|
|
406
|
+
},
|
|
407
|
+
finish_reason=samba_response[-1]['choices'][0]['finish_reason']
|
|
408
|
+
or None,
|
|
409
|
+
)
|
|
410
|
+
]
|
|
411
|
+
|
|
412
|
+
obj = ChatCompletion.construct(
|
|
413
|
+
id=first_chunk['id'],
|
|
414
|
+
choices=choices,
|
|
415
|
+
created=first_chunk['created'],
|
|
416
|
+
model=first_chunk['model'],
|
|
417
|
+
object="chat.completion",
|
|
418
|
+
usage=None,
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
return obj
|
|
422
|
+
|
|
338
423
|
def _sambaverse_to_openai_response(
|
|
339
424
|
self, samba_response: Dict[str, Any]
|
|
340
425
|
) -> ChatCompletion:
|
|
@@ -384,6 +469,16 @@ class SambaModel(BaseModelBackend):
|
|
|
384
469
|
|
|
385
470
|
return obj
|
|
386
471
|
|
|
472
|
+
@property
|
|
473
|
+
def token_limit(self) -> int:
|
|
474
|
+
r"""Returns the maximum token limit for the given model.
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
int: The maximum token limit for the given model.
|
|
478
|
+
"""
|
|
479
|
+
max_tokens = self.model_config_dict["max_tokens"]
|
|
480
|
+
return max_tokens
|
|
481
|
+
|
|
387
482
|
@property
|
|
388
483
|
def stream(self) -> bool:
|
|
389
484
|
r"""Returns whether the model is in stream mode, which sends partial
|
camel/models/stub_model.py
CHANGED
|
@@ -51,8 +51,8 @@ class StubModel(BaseModelBackend):
|
|
|
51
51
|
|
|
52
52
|
def __init__(
|
|
53
53
|
self,
|
|
54
|
-
model_type:
|
|
55
|
-
model_config_dict:
|
|
54
|
+
model_type: ModelType,
|
|
55
|
+
model_config_dict: Dict[str, Any],
|
|
56
56
|
api_key: Optional[str] = None,
|
|
57
57
|
url: Optional[str] = None,
|
|
58
58
|
token_counter: Optional[BaseTokenCounter] = None,
|
camel/models/togetherai_model.py
CHANGED
|
@@ -17,14 +17,9 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
17
17
|
|
|
18
18
|
from openai import OpenAI, Stream
|
|
19
19
|
|
|
20
|
-
from camel.configs import TOGETHERAI_API_PARAMS
|
|
20
|
+
from camel.configs import TOGETHERAI_API_PARAMS
|
|
21
21
|
from camel.messages import OpenAIMessage
|
|
22
|
-
from camel.
|
|
23
|
-
from camel.types import (
|
|
24
|
-
ChatCompletion,
|
|
25
|
-
ChatCompletionChunk,
|
|
26
|
-
ModelType,
|
|
27
|
-
)
|
|
22
|
+
from camel.types import ChatCompletion, ChatCompletionChunk, ModelType
|
|
28
23
|
from camel.utils import (
|
|
29
24
|
BaseTokenCounter,
|
|
30
25
|
OpenAITokenCounter,
|
|
@@ -32,50 +27,45 @@ from camel.utils import (
|
|
|
32
27
|
)
|
|
33
28
|
|
|
34
29
|
|
|
35
|
-
class TogetherAIModel
|
|
30
|
+
class TogetherAIModel:
|
|
36
31
|
r"""Constructor for Together AI backend with OpenAI compatibility.
|
|
37
|
-
|
|
38
|
-
Args:
|
|
39
|
-
model_type (Union[ModelType, str]): Model for which a backend is
|
|
40
|
-
created, supported model can be found here:
|
|
41
|
-
https://docs.together.ai/docs/chat-models
|
|
42
|
-
model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
|
|
43
|
-
that will be fed into:obj:`openai.ChatCompletion.create()`. If
|
|
44
|
-
:obj:`None`, :obj:`TogetherAIConfig().as_dict()` will be used.
|
|
45
|
-
(default: :obj:`None`)
|
|
46
|
-
api_key (Optional[str], optional): The API key for authenticating with
|
|
47
|
-
the Together service. (default: :obj:`None`)
|
|
48
|
-
url (Optional[str], optional): The url to the Together AI service.
|
|
49
|
-
If not provided, "https://api.together.xyz/v1" will be used.
|
|
50
|
-
(default: :obj:`None`)
|
|
51
|
-
token_counter (Optional[BaseTokenCounter], optional): Token counter to
|
|
52
|
-
use for the model. If not provided, :obj:`OpenAITokenCounter(
|
|
53
|
-
ModelType.GPT_4O_MINI)` will be used.
|
|
32
|
+
TODO: Add function calling support
|
|
54
33
|
"""
|
|
55
34
|
|
|
56
35
|
def __init__(
|
|
57
36
|
self,
|
|
58
|
-
model_type:
|
|
59
|
-
model_config_dict:
|
|
37
|
+
model_type: str,
|
|
38
|
+
model_config_dict: Dict[str, Any],
|
|
60
39
|
api_key: Optional[str] = None,
|
|
61
40
|
url: Optional[str] = None,
|
|
62
41
|
token_counter: Optional[BaseTokenCounter] = None,
|
|
63
42
|
) -> None:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
43
|
+
r"""Constructor for TogetherAI backend.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
model_type (str): Model for which a backend is created, supported
|
|
47
|
+
model can be found here: https://docs.together.ai/docs/chat-models
|
|
48
|
+
model_config_dict (Dict[str, Any]): A dictionary that will
|
|
49
|
+
be fed into openai.ChatCompletion.create().
|
|
50
|
+
api_key (Optional[str]): The API key for authenticating with the
|
|
51
|
+
Together service. (default: :obj:`None`)
|
|
52
|
+
url (Optional[str]): The url to the Together AI service. (default:
|
|
53
|
+
:obj:`"https://api.together.xyz/v1"`)
|
|
54
|
+
token_counter (Optional[BaseTokenCounter]): Token counter to use
|
|
55
|
+
for the model. If not provided, `OpenAITokenCounter(ModelType.
|
|
56
|
+
GPT_4O_MINI)` will be used.
|
|
57
|
+
"""
|
|
58
|
+
self.model_type = model_type
|
|
59
|
+
self.model_config_dict = model_config_dict
|
|
60
|
+
self._token_counter = token_counter
|
|
61
|
+
self._api_key = api_key or os.environ.get("TOGETHER_API_KEY")
|
|
62
|
+
self._url = url or os.environ.get("TOGETHER_API_BASE_URL")
|
|
73
63
|
|
|
74
64
|
self._client = OpenAI(
|
|
75
65
|
timeout=60,
|
|
76
66
|
max_retries=3,
|
|
77
67
|
api_key=self._api_key,
|
|
78
|
-
base_url=self._url,
|
|
68
|
+
base_url=self._url or "https://api.together.xyz/v1",
|
|
79
69
|
)
|
|
80
70
|
|
|
81
71
|
@api_keys_required("TOGETHER_API_KEY")
|
|
@@ -140,3 +130,19 @@ class TogetherAIModel(BaseModelBackend):
|
|
|
140
130
|
bool: Whether the model is in stream mode.
|
|
141
131
|
"""
|
|
142
132
|
return self.model_config_dict.get('stream', False)
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def token_limit(self) -> int:
|
|
136
|
+
r"""Returns the maximum token limit for the given model.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
int: The maximum token limit for the given model.
|
|
140
|
+
"""
|
|
141
|
+
max_tokens = self.model_config_dict.get("max_tokens")
|
|
142
|
+
if isinstance(max_tokens, int):
|
|
143
|
+
return max_tokens
|
|
144
|
+
print(
|
|
145
|
+
"Must set `max_tokens` as an integer in `model_config_dict` when"
|
|
146
|
+
" setting up the model. Using 4096 as default value."
|
|
147
|
+
)
|
|
148
|
+
return 4096
|
camel/models/vllm_model.py
CHANGED
|
@@ -17,66 +17,58 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
17
17
|
|
|
18
18
|
from openai import OpenAI, Stream
|
|
19
19
|
|
|
20
|
-
from camel.configs import VLLM_API_PARAMS
|
|
20
|
+
from camel.configs import VLLM_API_PARAMS
|
|
21
21
|
from camel.messages import OpenAIMessage
|
|
22
|
-
from camel.
|
|
23
|
-
from camel.types import (
|
|
24
|
-
ChatCompletion,
|
|
25
|
-
ChatCompletionChunk,
|
|
26
|
-
ModelType,
|
|
27
|
-
)
|
|
22
|
+
from camel.types import ChatCompletion, ChatCompletionChunk, ModelType
|
|
28
23
|
from camel.utils import BaseTokenCounter, OpenAITokenCounter
|
|
29
24
|
|
|
30
25
|
|
|
31
26
|
# flake8: noqa: E501
|
|
32
|
-
class VLLMModel
|
|
33
|
-
r"""vLLM service interface.
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
model_type (Union[ModelType, str]): Model for which a backend is
|
|
37
|
-
created.
|
|
38
|
-
model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
|
|
39
|
-
that will be fed into:obj:`openai.ChatCompletion.create()`. If
|
|
40
|
-
:obj:`None`, :obj:`VLLMConfig().as_dict()` will be used.
|
|
41
|
-
(default: :obj:`None`)
|
|
42
|
-
api_key (Optional[str], optional): The API key for authenticating with
|
|
43
|
-
the model service. vLLM doesn't need API key, it would be ignored
|
|
44
|
-
if set. (default: :obj:`None`)
|
|
45
|
-
url (Optional[str], optional): The url to the model service. If not
|
|
46
|
-
provided, :obj:`"http://localhost:8000/v1"` will be used.
|
|
47
|
-
(default: :obj:`None`)
|
|
48
|
-
token_counter (Optional[BaseTokenCounter], optional): Token counter to
|
|
49
|
-
use for the model. If not provided, :obj:`OpenAITokenCounter(
|
|
50
|
-
ModelType.GPT_4O_MINI)` will be used.
|
|
51
|
-
(default: :obj:`None`)
|
|
52
|
-
|
|
53
|
-
References:
|
|
54
|
-
https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html
|
|
55
|
-
"""
|
|
27
|
+
class VLLMModel:
|
|
28
|
+
r"""vLLM service interface."""
|
|
56
29
|
|
|
57
30
|
def __init__(
|
|
58
31
|
self,
|
|
59
|
-
model_type:
|
|
60
|
-
model_config_dict:
|
|
61
|
-
api_key: Optional[str] = None,
|
|
32
|
+
model_type: str,
|
|
33
|
+
model_config_dict: Dict[str, Any],
|
|
62
34
|
url: Optional[str] = None,
|
|
35
|
+
api_key: Optional[str] = None,
|
|
63
36
|
token_counter: Optional[BaseTokenCounter] = None,
|
|
64
37
|
) -> None:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
38
|
+
r"""Constructor for vLLM backend with OpenAI compatibility.
|
|
39
|
+
|
|
40
|
+
# Reference: https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
model_type (str): Model for which a backend is created.
|
|
44
|
+
model_config_dict (Dict[str, Any]): A dictionary that will
|
|
45
|
+
be fed into openai.ChatCompletion.create().
|
|
46
|
+
url (Optional[str]): The url to the model service. (default:
|
|
47
|
+
:obj:`"http://localhost:8000/v1"`)
|
|
48
|
+
api_key (Optional[str]): The API key for authenticating with the
|
|
49
|
+
model service.
|
|
50
|
+
token_counter (Optional[BaseTokenCounter]): Token counter to use
|
|
51
|
+
for the model. If not provided, `OpenAITokenCounter(ModelType.
|
|
52
|
+
GPT_4O_MINI)` will be used.
|
|
53
|
+
"""
|
|
54
|
+
self.model_type = model_type
|
|
55
|
+
self.model_config_dict = model_config_dict
|
|
56
|
+
self._url = (
|
|
57
|
+
url
|
|
58
|
+
or os.environ.get("VLLM_BASE_URL")
|
|
59
|
+
or "http://localhost:8000/v1"
|
|
70
60
|
)
|
|
71
|
-
if not
|
|
61
|
+
if not url and not os.environ.get("VLLM_BASE_URL"):
|
|
72
62
|
self._start_server()
|
|
73
63
|
# Use OpenAI cilent as interface call vLLM
|
|
74
64
|
self._client = OpenAI(
|
|
75
65
|
timeout=60,
|
|
76
66
|
max_retries=3,
|
|
77
|
-
api_key="Set-but-ignored", # required but ignored
|
|
78
67
|
base_url=self._url,
|
|
68
|
+
api_key=api_key,
|
|
79
69
|
)
|
|
70
|
+
self._token_counter = token_counter
|
|
71
|
+
self.check_model_config()
|
|
80
72
|
|
|
81
73
|
def _start_server(self) -> None:
|
|
82
74
|
r"""Starts the vllm server in a subprocess."""
|
|
@@ -86,9 +78,8 @@ class VLLMModel(BaseModelBackend):
|
|
|
86
78
|
stdout=subprocess.PIPE,
|
|
87
79
|
stderr=subprocess.PIPE,
|
|
88
80
|
)
|
|
89
|
-
self._url = "http://localhost:8000/v1"
|
|
90
81
|
print(
|
|
91
|
-
f"vllm server started on
|
|
82
|
+
f"vllm server started on http://localhost:8000/v1 "
|
|
92
83
|
f"for {self.model_type} model."
|
|
93
84
|
)
|
|
94
85
|
except Exception as e:
|
|
@@ -144,6 +135,22 @@ class VLLMModel(BaseModelBackend):
|
|
|
144
135
|
)
|
|
145
136
|
return response
|
|
146
137
|
|
|
138
|
+
@property
|
|
139
|
+
def token_limit(self) -> int:
|
|
140
|
+
r"""Returns the maximum token limit for the given model.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
int: The maximum token limit for the given model.
|
|
144
|
+
"""
|
|
145
|
+
max_tokens = self.model_config_dict.get("max_tokens")
|
|
146
|
+
if isinstance(max_tokens, int):
|
|
147
|
+
return max_tokens
|
|
148
|
+
print(
|
|
149
|
+
"Must set `max_tokens` as an integer in `model_config_dict` when"
|
|
150
|
+
" setting up the model. Using 4096 as default value."
|
|
151
|
+
)
|
|
152
|
+
return 4096
|
|
153
|
+
|
|
147
154
|
@property
|
|
148
155
|
def stream(self) -> bool:
|
|
149
156
|
r"""Returns whether the model is in stream mode, which sends partial
|