Skip to content

Commit a422dfd

Browse files
zjrwtxWendong-Fan
andauthored
feat:add Netmind platform (camel-ai#2268)
Co-authored-by: Wendong-Fan <[email protected]> Co-authored-by: Wendong <[email protected]>
1 parent 617e7cc commit a422dfd

File tree

12 files changed

+358
-0
lines changed

12 files changed

+358
-0
lines changed

.github/workflows/build_package.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ jobs:
106106
PPIO_API_KEY: "${{ secrets.PPIO_API_KEY }}"
107107
BEDROCK_API_KEY: "${{ secrets.BEDROCK_API_KEY }}"
108108
BEDROCK_API_BASE_URL: "${{ secrets.BEDROCK_API_BASE_URL }}"
109+
NETMIND_API_KEY: "${{ secrets.NETMIND_API_KEY }}"
109110
run: |
110111
source test_venv/bin/activate
111112
pytest --fast-test-mode ./test

.github/workflows/pytest_package.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ jobs:
7171
PPIO_API_KEY: "${{ secrets.PPIO_API_KEY }}"
7272
BEDROCK_API_KEY: "${{ secrets.BEDROCK_API_KEY }}"
7373
BEDROCK_API_BASE_URL: "${{ secrets.BEDROCK_API_BASE_URL }}"
74+
NETMIND_API_KEY: "${{ secrets.NETMIND_API_KEY }}"
7475
run: |
7576
source .venv/bin/activate
7677
uv pip install -e ".[all, dev, docs]"
@@ -134,6 +135,7 @@ jobs:
134135
PPIO_API_KEY: "${{ secrets.PPIO_API_KEY }}"
135136
BEDROCK_API_KEY: "${{ secrets.BEDROCK_API_KEY }}"
136137
BEDROCK_API_BASE_URL: "${{ secrets.BEDROCK_API_BASE_URL }}"
138+
NETMIND_API_KEY: "${{ secrets.NETMIND_API_KEY }}"
137139
run: |
138140
source .venv/bin/activate
139141
uv pip install -e ".[all, dev, docs]"
@@ -195,6 +197,7 @@ jobs:
195197
PPIO_API_KEY: "${{ secrets.PPIO_API_KEY }}"
196198
BEDROCK_API_KEY: "${{ secrets.BEDROCK_API_KEY }}"
197199
BEDROCK_API_BASE_URL: "${{ secrets.BEDROCK_API_BASE_URL }}"
200+
NETMIND_API_KEY: "${{ secrets.NETMIND_API_KEY }}"
198201
run: |
199202
source .venv/bin/activate
200203
uv pip install -e ".[all, dev, docs]"

camel/configs/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from .mistral_config import MISTRAL_API_PARAMS, MistralConfig
2626
from .modelscope_config import MODELSCOPE_API_PARAMS, ModelScopeConfig
2727
from .moonshot_config import MOONSHOT_API_PARAMS, MoonshotConfig
28+
from .netmind_config import NETMIND_API_PARAMS, NetmindConfig
2829
from .nvidia_config import NVIDIA_API_PARAMS, NvidiaConfig
2930
from .ollama_config import OLLAMA_API_PARAMS, OllamaConfig
3031
from .openai_config import OPENAI_API_PARAMS, ChatGPTConfig
@@ -55,6 +56,8 @@
5556
'GroqConfig',
5657
'LiteLLMConfig',
5758
'LITELLM_API_PARAMS',
59+
'NetmindConfig',
60+
'NETMIND_API_PARAMS',
5861
'NvidiaConfig',
5962
'NVIDIA_API_PARAMS',
6063
'OllamaConfig',

camel/configs/netmind_config.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
from __future__ import annotations
15+
16+
from typing import Dict, List, Optional, Union
17+
18+
from pydantic import Field
19+
20+
from camel.configs.base_config import BaseConfig
21+
from camel.types import NotGiven
22+
23+
24+
class NetmindConfig(BaseConfig):
25+
r"""Defines the parameters for generating chat completions using OpenAI
26+
compatibility.
27+
28+
Reference: https://netmind-power.gitbook.io/netmind-power-documentation/
29+
api/inference/chat
30+
31+
Args:
32+
presence_penalty (float, optional): Number between :obj:`-2.0` and
33+
:obj:`2.0`. Positive values penalize new tokens based on whether
34+
they appear in the text so far, increasing the model's likelihood
35+
to talk about new topics. See more information about frequency and
36+
presence penalties. (default: :obj:`None`)
37+
frequency_penalty (float, optional): Number between :obj:`-2.0` and
38+
:obj:`2.0`. Positive values penalize new tokens based on their
39+
existing frequency in the text so far, decreasing the model's
40+
likelihood to repeat the same line verbatim. See more information
41+
about frequency and presence penalties. (default: :obj:`None`)
42+
repetition_penalty (float, optional): Penalizes new tokens based on
43+
their appearance in the prompt and generated text.
44+
(default: :obj:`None`)
45+
stream (bool, optional): Whether to stream the response.
46+
(default: :obj:`None`)
47+
temperature (float, optional): Controls randomness in the response.
48+
Higher values make output more random, lower values make it more
49+
deterministic. Range: [0.0, 2.0]. (default: :obj:`None`)
50+
top_p (float, optional): Controls diversity via nucleus sampling.
51+
Range: [0.0, 1.0]. (default: :obj:`None`)
52+
logit_bias (dict, optional): Modify the likelihood of specified tokens
53+
appearing in the completion. Accepts a json object that maps tokens
54+
(specified by their token ID in the tokenizer) to an associated
55+
bias value from :obj:`-100` to :obj:`100`. Mathematically, the bias
56+
is added to the logits generated by the model prior to sampling.
57+
The exact effect will vary per model, but values between:obj:` -1`
58+
and :obj:`1` should decrease or increase likelihood of selection;
59+
values like :obj:`-100` or :obj:`100` should result in a ban or
60+
exclusive selection of the relevant token. (default: :obj:`None`)
61+
max_tokens (Union[int, NotGiven], optional): Maximum number of tokens
62+
to generate. If not provided, model will use its default maximum.
63+
(default: :obj:`None`)
64+
stop (Optional[List[str]], optional): List of stop sequences.
65+
(default: :obj:`None`)
66+
n (Optional[int], optional): Number of chat completion choices to
67+
generate for each input message. (default: :obj:`None`)
68+
"""
69+
70+
stream: Optional[bool] = Field(default=None)
71+
temperature: Optional[float] = Field(default=None)
72+
top_p: Optional[float] = Field(default=None)
73+
presence_penalty: Optional[float] = Field(default=None)
74+
frequency_penalty: Optional[float] = Field(default=None)
75+
repetition_penalty: Optional[float] = Field(default=None)
76+
max_tokens: Optional[Union[int, NotGiven]] = Field(default=None)
77+
stop: Optional[List[str]] = Field(default=None)
78+
n: Optional[int] = Field(default=None)
79+
logit_bias: Optional[Dict[str, float]] = Field(default=None)
80+
81+
82+
NETMIND_API_PARAMS = {param for param in NetmindConfig.model_fields.keys()}

camel/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from .modelscope_model import ModelScopeModel
3232
from .moonshot_model import MoonshotModel
3333
from .nemotron_model import NemotronModel
34+
from .netmind_model import NetmindModel
3435
from .nvidia_model import NvidiaModel
3536
from .ollama_model import OllamaModel
3637
from .openai_audio_models import OpenAIAudioModels
@@ -65,6 +66,7 @@
6566
'ModelManager',
6667
'LiteLLMModel',
6768
'OpenAIAudioModels',
69+
'NetmindModel',
6870
'NemotronModel',
6971
'NvidiaModel',
7072
'OllamaModel',

camel/models/model_factory.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from camel.models.mistral_model import MistralModel
3232
from camel.models.modelscope_model import ModelScopeModel
3333
from camel.models.moonshot_model import MoonshotModel
34+
from camel.models.netmind_model import NetmindModel
3435
from camel.models.nvidia_model import NvidiaModel
3536
from camel.models.ollama_model import OllamaModel
3637
from camel.models.openai_compatible_model import OpenAICompatibleModel
@@ -123,6 +124,8 @@ def create(
123124
model_class = AIMLModel
124125
elif model_platform.is_volcano:
125126
model_class = VolcanoModel
127+
elif model_platform.is_netmind:
128+
model_class = NetmindModel
126129

127130
elif model_platform.is_openai and model_type.is_openai:
128131
model_class = OpenAIModel

camel/models/netmind_model.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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 os
16+
from typing import Any, Dict, Optional, Union
17+
18+
from camel.configs import NETMIND_API_PARAMS, NetmindConfig
19+
from camel.models.openai_compatible_model import OpenAICompatibleModel
20+
from camel.types import ModelType
21+
from camel.utils import (
22+
BaseTokenCounter,
23+
api_keys_required,
24+
)
25+
26+
27+
class NetmindModel(OpenAICompatibleModel):
28+
r"""Constructor for Netmind backend with OpenAI compatibility.
29+
30+
Args:
31+
model_type (Union[ModelType, str]): Model for which a backend is
32+
created, supported model can be found here:
33+
https://www.netmind.ai/modelsLibrary?expandList=Chat
34+
model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
35+
that will be fed into:obj:`openai.ChatCompletion.create()`. If
36+
:obj:`None`, :obj:`NetmindConfig().as_dict()` will be used.
37+
(default: :obj:`None`)
38+
api_key (Optional[str], optional): The API key for authenticating with
39+
the Netmind service. (default: :obj:`None`)
40+
url (Optional[str], optional): The url to the Netmind service.
41+
If not provided, "https://api.netmind.ai/inference-api/openai/v1"
42+
will be used.(default: :obj:`None`)
43+
token_counter (Optional[BaseTokenCounter], optional): Token counter to
44+
use for the model. If not provided, :obj:`OpenAITokenCounter(
45+
ModelType.GPT_4O_MINI)` will be used.
46+
timeout (Optional[float], optional): The timeout value in seconds for
47+
API calls. If not provided, will fall back to the MODEL_TIMEOUT
48+
environment variable or default to 180 seconds.
49+
(default: :obj:`None`)
50+
"""
51+
52+
@api_keys_required(
53+
[
54+
("api_key", 'NETMIND_API_KEY'),
55+
]
56+
)
57+
def __init__(
58+
self,
59+
model_type: Union[ModelType, str],
60+
model_config_dict: Optional[Dict[str, Any]] = None,
61+
api_key: Optional[str] = None,
62+
url: Optional[str] = None,
63+
token_counter: Optional[BaseTokenCounter] = None,
64+
timeout: Optional[float] = None,
65+
) -> None:
66+
if model_config_dict is None:
67+
model_config_dict = NetmindConfig().as_dict()
68+
api_key = api_key or os.environ.get("NETMIND_API_KEY")
69+
url = url or os.environ.get(
70+
"NETMIND_API_BASE_URL",
71+
"https://api.netmind.ai/inference-api/openai/v1",
72+
)
73+
timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
74+
super().__init__(
75+
model_type=model_type,
76+
model_config_dict=model_config_dict,
77+
api_key=api_key,
78+
url=url,
79+
token_counter=token_counter,
80+
timeout=timeout,
81+
)
82+
83+
def check_model_config(self):
84+
r"""Check whether the model configuration contains any
85+
unexpected arguments to NETMIND API.
86+
87+
Raises:
88+
ValueError: If the model configuration dictionary contains any
89+
unexpected arguments to NETMIND API.
90+
"""
91+
for param in self.model_config_dict:
92+
if param not in NETMIND_API_PARAMS:
93+
raise ValueError(
94+
f"Unexpected argument `{param}` is "
95+
"input into NETMIND model backend."
96+
)

camel/types/enums.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,18 @@ class ModelType(UnifiedModelType, Enum):
149149
CLAUDE_3_5_HAIKU = "claude-3-5-haiku-latest"
150150
CLAUDE_3_7_SONNET = "claude-3-7-sonnet-latest"
151151

152+
# Netmind models
153+
NETMIND_LLAMA_4_MAVERICK_17B_128E_INSTRUCT = (
154+
"meta-llama/Llama-4-Maverick-17B-128E-Instruct"
155+
)
156+
NETMIND_LLAMA_4_SCOUT_17B_16E_INSTRUCT = (
157+
"meta-llama/Llama-4-Scout-17B-16E-Instruct"
158+
)
159+
NETMIND_DEEPSEEK_R1 = "deepseek-ai/DeepSeek-R1"
160+
NETMIND_DEEPSEEK_V3 = "deepseek-ai/DeepSeek-V3-0324"
161+
NETMIND_DOUBAO_1_5_PRO = "doubao/Doubao-1.5-pro"
162+
NETMIND_QWQ_32B = "Qwen/QwQ-32B"
163+
152164
# Nvidia models
153165
NVIDIA_NEMOTRON_340B_INSTRUCT = "nvidia/nemotron-4-340b-instruct"
154166
NVIDIA_NEMOTRON_340B_REWARD = "nvidia/nemotron-4-340b-reward"
@@ -606,6 +618,17 @@ def is_deepseek(self) -> bool:
606618
ModelType.DEEPSEEK_REASONER,
607619
}
608620

621+
@property
622+
def is_netmind(self) -> bool:
623+
return self in {
624+
ModelType.NETMIND_LLAMA_4_MAVERICK_17B_128E_INSTRUCT,
625+
ModelType.NETMIND_LLAMA_4_SCOUT_17B_16E_INSTRUCT,
626+
ModelType.NETMIND_DEEPSEEK_R1,
627+
ModelType.NETMIND_DEEPSEEK_V3,
628+
ModelType.NETMIND_DOUBAO_1_5_PRO,
629+
ModelType.NETMIND_QWQ_32B,
630+
}
631+
609632
@property
610633
def is_ppio(self) -> bool:
611634
return self in {
@@ -759,6 +782,11 @@ def token_limit(self) -> int:
759782
ModelType.PPIO_YI_1_5_34B_CHAT,
760783
}:
761784
return 16_384
785+
786+
elif self in {
787+
ModelType.NETMIND_DOUBAO_1_5_PRO,
788+
}:
789+
return 32_000
762790
elif self in {
763791
ModelType.MISTRAL_CODESTRAL,
764792
ModelType.MISTRAL_7B,
@@ -814,6 +842,7 @@ def token_limit(self) -> int:
814842
ModelType.PPIO_DEEPSEEK_R1,
815843
ModelType.PPIO_DEEPSEEK_V3,
816844
ModelType.AWS_DEEPSEEK_R1,
845+
ModelType.NETMIND_QWQ_32B,
817846
}:
818847
return 64_000
819848
elif self in {
@@ -863,6 +892,8 @@ def token_limit(self) -> int:
863892
ModelType.AWS_LLAMA_3_3_70B_INSTRUCT,
864893
ModelType.AWS_LLAMA_3_2_90B_INSTRUCT,
865894
ModelType.AWS_LLAMA_3_2_11B_INSTRUCT,
895+
ModelType.NETMIND_DEEPSEEK_R1,
896+
ModelType.NETMIND_DEEPSEEK_V3,
866897
}:
867898
return 128_000
868899
elif self in {
@@ -906,8 +937,14 @@ def token_limit(self) -> int:
906937
ModelType.OPENROUTER_LLAMA_4_MAVERICK_FREE,
907938
}:
908939
return 256_000
940+
941+
elif self in {
942+
ModelType.NETMIND_LLAMA_4_SCOUT_17B_16E_INSTRUCT,
943+
}:
944+
return 320_000
909945
elif self in {
910946
ModelType.OPENROUTER_LLAMA_4_SCOUT_FREE,
947+
ModelType.NETMIND_LLAMA_4_MAVERICK_17B_128E_INSTRUCT,
911948
}:
912949
return 512_000
913950
elif self in {
@@ -1121,6 +1158,7 @@ class ModelPlatformType(Enum):
11211158
SILICONFLOW = "siliconflow"
11221159
AIML = "aiml"
11231160
VOLCANO = "volcano"
1161+
NETMIND = "netmind"
11241162

11251163
@classmethod
11261164
def from_name(cls, name):
@@ -1246,6 +1284,11 @@ def is_deepseek(self) -> bool:
12461284
r"""Returns whether this platform is DeepSeek."""
12471285
return self is ModelPlatformType.DEEPSEEK
12481286

1287+
@property
1288+
def is_netmind(self) -> bool:
1289+
r"""Returns whether this platform is Netmind."""
1290+
return self is ModelPlatformType.NETMIND
1291+
12491292
@property
12501293
def is_ppio(self) -> bool:
12511294
r"""Returns whether this platform is PPIO."""

camel/types/unified_model_type.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ def is_mistral(self) -> bool:
113113
r"""Returns whether the model is a Mistral model."""
114114
return True
115115

116+
@property
117+
def is_netmind(self) -> bool:
118+
r"""Returns whether the model is a Netmind model."""
119+
return True
120+
116121
@property
117122
def is_reka(self) -> bool:
118123
r"""Returns whether the model is a Reka model."""

docs/key_modules/models.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ CAMEL supports a wide range of models, including [OpenAI’s GPT series](https:/
3535
| **LMStudio** | [supported models](https://lmstudio.ai/models) |
3636
| **vLLM** | [supported models](https://docs.vllm.ai/en/latest/models/supported_models.html) |
3737
| **SGLANG** | [supported models](https://sgl-project.github.io/references/supported_models.html) |
38+
| **NetMind** | [supported models](https://www.netmind.ai/modelsLibrary) |
3839
| **NVIDIA** | [supported models](https://docs.api.nvidia.com/nim/reference/llm-apis) |
3940
| **AIML** | [supported models](https://docs.aimlapi.com/api-overview/model-database/text-models) |
4041
| **ModelScope** | [supported models](https://www.modelscope.cn/docs/model-service/API-Inference/intro) |

0 commit comments

Comments
 (0)