Skip to content

Commit 9d846e2

Browse files
feat: add AiHubMix as a new model provider (#3338)
Co-authored-by: Wendong-Fan <[email protected]>
1 parent 586d4ff commit 9d846e2

File tree

7 files changed

+287
-1
lines changed

7 files changed

+287
-1
lines changed

camel/configs/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# limitations under the License.
1313
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
1414
from .aiml_config import AIML_API_PARAMS, AIMLConfig
15+
from .aihubmix_config import AIHUBMIX_API_PARAMS, AihubMixConfig
1516
from .amd_config import AMD_API_PARAMS, AMDConfig
1617
from .anthropic_config import ANTHROPIC_API_PARAMS, AnthropicConfig
1718
from .base_config import BaseConfig
@@ -57,6 +58,8 @@
5758
'BaseConfig',
5859
'ChatGPTConfig',
5960
'OPENAI_API_PARAMS',
61+
'AihubMixConfig',
62+
'AIHUBMIX_API_PARAMS',
6063
'AnthropicConfig',
6164
'ANTHROPIC_API_PARAMS',
6265
'GROQ_API_PARAMS',
@@ -127,4 +130,4 @@
127130
'QIANFAN_API_PARAMS',
128131
'CrynuxConfig',
129132
'CRYNUX_API_PARAMS',
130-
]
133+
]

camel/configs/aihubmix_config.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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, Optional, Sequence, Type, Union
17+
18+
from pydantic import BaseModel
19+
20+
from camel.configs.base_config import BaseConfig
21+
22+
23+
class AihubMixConfig(BaseConfig):
24+
r"""Defines the parameters for generating chat completions using the
25+
AihubMix API.
26+
27+
Args:
28+
temperature (float, optional): Sampling temperature to use, between
29+
:obj:`0` and :obj:`2`. Higher values make the output more random,
30+
while lower values make it more focused and deterministic.
31+
(default: :obj:`0.8`)
32+
max_tokens (int, optional): The maximum number of tokens to generate
33+
in the chat completion. The total length of input tokens and
34+
generated tokens is limited by the model's context length.
35+
(default: :obj:`1024`)
36+
top_p (float, optional): An alternative to sampling with temperature,
37+
called nucleus sampling, where the model considers the results of
38+
the tokens with top_p probability mass. So :obj:`0.1` means only
39+
the tokens comprising the top 10% probability mass are considered.
40+
(default: :obj:`1`)
41+
frequency_penalty (float, optional): Number between :obj:`-2.0` and
42+
:obj:`2.0`. Positive values penalize new tokens based on their
43+
existing frequency in the text so far, decreasing the model's
44+
likelihood to repeat the same line verbatim.
45+
(default: :obj:`0`)
46+
presence_penalty (float, optional): Number between :obj:`-2.0` and
47+
:obj:`2.0`. Positive values penalize new tokens based on whether
48+
they appear in the text so far, increasing the model's likelihood
49+
to talk about new topics.
50+
(default: :obj:`0`)
51+
stream (bool, optional): If True, partial message deltas will be sent
52+
as data-only server-sent events as they become available.
53+
(default: :obj:`False`)
54+
web_search_options (dict, optional): Search model's web search options,
55+
only supported by specific search models.
56+
(default: :obj:`None`)
57+
tools (list[FunctionTool], optional): A list of tools the model may
58+
call. Currently, only functions are supported as a tool. Use this
59+
to provide a list of functions the model may generate JSON inputs
60+
for. A max of 128 functions are supported.
61+
tool_choice (Union[dict[str, str], str], optional): Controls which (if
62+
any) tool is called by the model. :obj:`"none"` means the model
63+
will not call any tool and instead generates a message.
64+
:obj:`"auto"` means the model can pick between generating a
65+
message or calling one or more tools. :obj:`"required"` means the
66+
model must call one or more tools. Specifying a particular tool
67+
via {"type": "function", "function": {"name": "my_function"}}
68+
forces the model to call that tool. :obj:`"none"` is the default
69+
when no tools are present. :obj:`"auto"` is the default if tools
70+
are present.
71+
parallel_tool_calls (bool, optional): A parameter specifying whether
72+
the model should call tools in parallel or not.
73+
(default: :obj:`None`)
74+
extra_headers: Optional[Dict[str, str]]: Extra headers to use for the
75+
model. (default: :obj:`None`)
76+
"""
77+
78+
temperature: Optional[float] = 0.8
79+
max_tokens: Optional[int] = 1024
80+
top_p: Optional[float] = 1.0
81+
frequency_penalty: Optional[float] = 0.0
82+
presence_penalty: Optional[float] = 0.0
83+
stream: Optional[bool] = False
84+
web_search_options: Optional[Dict] = None
85+
tool_choice: Optional[Union[Dict[str, str], str]] = None
86+
parallel_tool_calls: Optional[bool] = None
87+
extra_headers: Optional[Dict[str, str]] = None
88+
89+
90+
AIHUBMIX_API_PARAMS = {param for param in AihubMixConfig.model_fields.keys()}

camel/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# See the License for the specific language governing permissions and
1212
# limitations under the License.
1313
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14+
from .aihubmix_model import AihubMixModel
1415
from .aiml_model import AIMLModel
1516
from .amd_model import AMDModel
1617
from .anthropic_model import AnthropicModel
@@ -106,4 +107,5 @@
106107
'WatsonXModel',
107108
'QianfanModel',
108109
'CrynuxModel',
110+
'AihubMixModel',
109111
]

camel/models/aihubmix_model.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
import os
15+
from typing import Any, Dict, Optional, Union
16+
17+
from camel.models.openai_compatible_model import OpenAICompatibleModel
18+
from camel.types import ModelType
19+
from camel.utils import (
20+
BaseTokenCounter,
21+
api_keys_required,
22+
)
23+
24+
25+
class AihubMixModel(OpenAICompatibleModel):
26+
r"""AihubMix API in a unified OpenAICompatibleModel interface.
27+
28+
Args:
29+
model_type (Union[ModelType, str]): Model for which a backend is
30+
created.
31+
model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
32+
that will be fed into OpenAI client. If :obj:`None`,
33+
:obj:`{}` will be used.
34+
(default: :obj:`None`)
35+
api_key (Optional[str], optional): The API key for authenticating with
36+
AihubMix service. (default: :obj:`None`)
37+
url (Optional[str], optional): The URL to AihubMix service. If
38+
not provided, :obj:`https://aihubmix.com/v1` will be used.
39+
(default: :obj:`None`)
40+
token_counter (Optional[BaseTokenCounter], optional): Token counter to
41+
use for the model. If not provided, :obj:`OpenAITokenCounter(
42+
ModelType.GPT_4O_MINI)` will be used.
43+
(default: :obj:`None`)
44+
timeout (Optional[float], optional): The timeout value in seconds for
45+
API calls. If not provided, will fall back to the MODEL_TIMEOUT
46+
environment variable or default to 180 seconds.
47+
(default: :obj:`None`)
48+
max_retries (int, optional): Maximum number of retries for API calls.
49+
(default: :obj:`3`)
50+
**kwargs (Any): Additional arguments to pass to the client
51+
initialization.
52+
"""
53+
54+
@api_keys_required([("api_key", "AIHUBMIX_API_KEY")])
55+
def __init__(
56+
self,
57+
model_type: Union[ModelType, str],
58+
model_config_dict: Optional[Dict[str, Any]] = None,
59+
api_key: Optional[str] = None,
60+
url: Optional[str] = None,
61+
token_counter: Optional[BaseTokenCounter] = None,
62+
timeout: Optional[float] = None,
63+
max_retries: int = 3,
64+
**kwargs: Any,
65+
) -> None:
66+
if model_config_dict is None:
67+
model_config_dict = {}
68+
api_key = api_key or os.environ.get("AIHUBMIX_API_KEY")
69+
url = url or os.environ.get(
70+
"AIHUBMIX_API_BASE_URL",
71+
"https://aihubmix.com/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+
max_retries=max_retries,
82+
**kwargs,
83+
)

camel/models/model_factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from camel.models.base_model import BaseModelBackend
2424
from camel.models.cohere_model import CohereModel
2525
from camel.models.cometapi_model import CometAPIModel
26+
from camel.models.aihubmix_model import AihubMixModel
2627
from camel.models.crynux_model import CrynuxModel
2728
from camel.models.deepseek_model import DeepSeekModel
2829
from camel.models.gemini_model import GeminiModel
@@ -107,6 +108,7 @@ class ModelFactory:
107108
ModelPlatformType.WATSONX: WatsonXModel,
108109
ModelPlatformType.QIANFAN: QianfanModel,
109110
ModelPlatformType.CRYNUX: CrynuxModel,
111+
ModelPlatformType.AIHUBMIX: AihubMixModel,
110112
}
111113

112114
@staticmethod

camel/types/enums.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,6 +1718,7 @@ class ModelPlatformType(Enum):
17181718
WATSONX = "watsonx"
17191719
QIANFAN = "qianfan"
17201720
CRYNUX = "crynux"
1721+
AIHUBMIX = "aihubmix"
17211722

17221723
@classmethod
17231724
def from_name(cls, name):
@@ -1898,6 +1899,11 @@ def is_crynux(self) -> bool:
18981899
r"""Returns whether this platform is Crynux."""
18991900
return self is ModelPlatformType.CRYNUX
19001901

1902+
@property
1903+
def is_aihubmix(self) -> bool:
1904+
r"""Returns whether this platform is AihubMix."""
1905+
return self is ModelPlatformType.AIHUBMIX
1906+
19011907

19021908
class AudioModelType(Enum):
19031909
TTS_1 = "tts-1"
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python3
2+
3+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
16+
17+
r"""Example of using AIHubMix models in CAMEL."""
18+
19+
import os
20+
21+
from camel.agents import ChatAgent
22+
from camel.configs import ChatGPTConfig
23+
from camel.models import ModelFactory
24+
from camel.types import ModelPlatformType, ModelType
25+
26+
27+
def test_aihubmix_model() -> None:
28+
r"""Test AIHubMix model using ModelFactory."""
29+
30+
# Set up the model
31+
# You need to set AIHUBMIX_API_KEY in your environment variables
32+
# or directly pass it as api_key parameter
33+
api_key = os.environ.get("AIHUBMIX_API_KEY")
34+
if not api_key:
35+
print("Skipping AIHubMix test - AIHUBMIX_API_KEY not set")
36+
return
37+
38+
model = ModelFactory.create(
39+
model_platform=ModelPlatformType.AIHUBMIX,
40+
model_type=ModelType.GPT_5,
41+
api_key=api_key,
42+
model_config_dict=ChatGPTConfig(temperature=0.2).as_dict(),
43+
)
44+
45+
# Set up the agent
46+
agent = ChatAgent(
47+
system_message="You are a helpful assistant.",
48+
model=model,
49+
)
50+
51+
# Test the agent
52+
user_msg = "Say hi to CAMEL AI community in a friendly way."
53+
response = agent.step(user_msg)
54+
55+
print(f"User message: {user_msg}")
56+
print(f"Agent response: {response.msg.content}")
57+
58+
59+
def test_aihubmix_with_custom_model() -> None:
60+
r"""Test AIHubMix model with a custom model name."""
61+
62+
# Set up the model
63+
api_key = os.environ.get("AIHUBMIX_API_KEY")
64+
if not api_key:
65+
print("Skipping AIHubMix custom model test - AIHUBMIX_API_KEY not set")
66+
return
67+
68+
model = ModelFactory.create(
69+
model_platform=ModelPlatformType.AIHUBMIX,
70+
model_type="gpt-4", # Using a string directly
71+
api_key=api_key,
72+
model_config_dict=ChatGPTConfig(temperature=0.2).as_dict(),
73+
)
74+
75+
# Set up the agent
76+
agent = ChatAgent(
77+
system_message="You are a helpful assistant.",
78+
model=model,
79+
)
80+
81+
# Test the agent
82+
user_msg = "Explain what is an AI agent in one sentence."
83+
response = agent.step(user_msg)
84+
85+
print(f"User message: {user_msg}")
86+
print(f"Agent response: {response.msg.content}")
87+
88+
89+
def main():
90+
r"""Main function to test AIHubMix models."""
91+
print("Testing AIHubMix models:")
92+
print("=" * 40)
93+
94+
test_aihubmix_model()
95+
print("-" * 40)
96+
test_aihubmix_with_custom_model()
97+
98+
99+
if __name__ == "__main__":
100+
main()

0 commit comments

Comments
 (0)